2010-10-12 6 views
1

Что такое эквивалент C# этого псевдокода?Перечислять имена/значения совпадений регулярных выражений

var pattern = ...; 
var lookup = new Dictionary<string, string>(); 

foreach (var group in new Regex(pattern).Matches()) 
{ 
    lookup[group.Name] = group.Value; 
} 

Я не вижу никаких System.Text.RegularExpressions связанных с групповым объекта, который предоставляет имя группы.

Что мне не хватает?

То, что я на самом деле пытаюсь сделать, это преобразовать файл со строками в следующем формате:

eventName|message|date 

К IEnumerable<EventLogLine> с EventLogLine существами:

public struct EventLogLine 
{ 
    public string EventName { get; set; } 
    public string Message { get; set; } 
    public DateTime Date { get; set; } 
} 

И поставить эти строки в IDictionary<string /*EventName*/, IEnumerable<EventLogLine>>.

ответ

0

Я только что сбил его с помощью LINQ. Он полагается на то, что List<string> будет заполнен строками в файле.

 var lines = new List<string>(); 
     var dict = lines.Select(l => 
     { 
      var sp = l.Split('|'); 
      return new EventLogLine { EventName = sp[0], Message = sp[1], Date = DateTime.Parse(sp[2]) }; 
     }) 
     .GroupBy(e => e.EventName) 
     .ToDictionary(grp => grp.Key, grp => grp.AsEnumerable()); 

В основном вы преобразовать каждую строку в EventLogLine, используя Select(), а затем использовать GroupBy(), чтобы создать свою группировку на основе EventName, затем с помощью ToDictionary() для выполнения запроса и создать свой словарь в требуемом формате!

0

См. Пример в Match.Groups MSDN article.. Думаю, вам стоит взглянуть на ответ Аластер, поскольку, поскольку ваш ввод настолько прост, вероятно, было бы легче прочитать код позже, если вы просто используете ReadLine и Split.

0

Рассмотрите возможность использования ToLookup, а не ToDictionary. Lookups работают естественным образом с linq и общим кодом в целом, будучи неизменными и выставляя очень простой API. Кроме того, я бы инкапсулировал разбор в структуру EventLogLine.

В результате код будет выглядеть следующим образом:

IEnumerable<string> lines; 

ILookup<string, EventLogLine> lookup = 
    lines.Select(EventLogLine.Parse).ToLookup(evtLine => evtLine.EventName); 

Пример потребитель:

if(lookup["HorribleEvent"].Any()) 
    Console.WriteLine("OMG, Horrible!"); 

foreach(var evt in lookup["FixableEvent"]) 
    FixIt(evt); 

var q = from evtName in relevantEventNames 
     from evt in lookup[evtName] 
     select MyProjection(evt); 

Обратите внимание, что вам не нужно, чтобы проверить ключ-существование, в отличии от Словаря :

if(dictionary.ContainsKey("HorribleEvent")) //&& dictionary["HorribleEvent"].Any() sometimes needed 
    Console.WriteLine("OMG, Horrible!"); 

if(dictionary.ContainsKey("FixableEvent")) 
    foreach(var evt in lookup["FixableEvent"]) 
     FixIt(evt); 

var q = from evtName in relevantEventNames.Where(dictionary.ContainsKey) 
     from evt in dictionary[evtName] 
     select MyProjection(evt); 

Как вы можете заметить, работа со словарем, содержащим значения IEnumerable, tle triction - ILookup - это то, что вы хотите!

Наконец, модифицированный EventLogLine:

public struct EventLogLine { 
    public string EventName { get; private set; } 
    public string Message { get; private set; } 
    public DateTime Date { get; private set; } 

    public static EventLogLine Parse(string line) { 
     var splitline = line.Split('|'); 
     if(splitline.Length != 3) throw new ArgumentException("Invalid event log line"); 
     return new EventLogLine { 
      EventName = splitline[0], 
      Message = splitline[1], 
      Date = DateTime.Parse(splitline[2]), 
     }; 
    } 
} 
0

Чтобы ответить на эту часть вашего вопроса:

Я не вижу никаких System.Text.RegularExpressions связанных с групповой объект, который предоставляет имя группы . Что мне не хватает?

Я адаптировались-структуру Имон Nerbonne на использование регулярных выражений:

public struct EventLogLine 
{ 
    public string EventName { get; private set; } 
    public string Message { get; private set; } 
    public DateTime Date { get; private set; } 

    private static Regex expectedLineFormat = new Regex(
      @"^(?<eventName>[^|]*)\|(?<message>[^|]*)\|(?<date>[^|]*)$", 
      RegexOptions.Singleline | RegexOptions.Compiled 
    ); 

    public static EventLogLine Parse(string line) { 

     Match match = expectedLineFormat.Match(line); 

     if (match.Success) { 
      return new EventLogLine { 
       EventName = match.Groups["eventName"].ToString(), 
       Message = match.Groups["message"].ToString(), 
       Date = DateTime.Parse(match.Groups["date"].ToString() 
      }; 
     } 
     else { 
      throw new ArgumentException("Invalid event log line"); 
     } 
    } 
} 
0

Для более прямого ответа на свой вопрос (без комментариев на ваш подход), так как у меня была аналогичная проблема ...

Согласно Mono source code, перечисление для индексатора Groups основано на приватном поле Match.regex, поэтому вам нужно будет иметь Regex. Но если вы делаете, как вы были выше ...

public static Dictionary<string, string> ToDictionary(
    Regex regex, GroupCollection groups) 
{ 
    var groupDict = new Dictionary<string, string>(); 
    foreach (string name in regex.GetGroupNames()){ //the only way to get the names 
     Group namedGroup = groups[name]; //test for existence 
     if (namedGroup.Success) 
      groupDict.Add(name, namedGroup.Value); 
    } 
    return groupDict; 
} 

или, как Linq,

regex.GetGroupNames() 
    .Where(name => groups[name].Success) 
    .ToDictionary(name => name, name => groups[name].Value) 
Смежные вопросы