枚举正则表达式匹配名称/值

时间:2010-10-12 03:16:01

标签: c# regex parsing

这个伪代码的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 :(得分: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()运行查询并以所需格式创建您的字典!

答案 1 :(得分:0)

请参阅Match.Groups MSDN article.中的示例我认为您应该看看Alastair的答案,因为您的输入非常简单,如果您只是使用ReadLine和Split,可能会更容易阅读代码。

答案 2 :(得分:0)

考虑使用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]),
        };
    }
}

答案 3 :(得分:0)

回答你问题的这一部分:

  

我没有看到任何   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");
        }
    }
}

答案 4 :(得分:0)

更直接地回答你原来的问题(没有评论你的方法),因为我遇到了类似的问题......

根据Mono source codeGroups索引器的枚举基于私有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)