Перечислять имена / значения соответствия регулярному выражению - PullRequest
1 голос
/ 12 октября 2010

Что такое эквивалент 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>>.

Ответы [ 5 ]

0 голосов
/ 21 июля 2012

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

Согласно исходному коду Mono , перечисление для индексатора 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;
}

или, как Линк,

regex.GetGroupNames()
  .Where(name => groups[name].Success)
  .ToDictionary(name => name, name => groups[name].Value)
0 голосов
/ 12 октября 2010

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

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

Я адаптировал структуру Eamon 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 голосов
/ 12 октября 2010

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

0 голосов
/ 12 октября 2010

Попробуйте использовать ToLookup вместо ToDictionary. Поиски естественным образом работают с 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, возникает небольшое трение - 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 голосов
/ 12 октября 2010

Я только что понял это, используя 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() выполните запрос и создайте словарь в требуемом формате!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...