[英]Enumerate regex match names/values
该伪代码的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>>.
为了更直接地回答您的原始问题(不对您的方法发表评论),因为我遇到了类似的问题...
根据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;
}
或者,作为Linq,
regex.GetGroupNames()
.Where(name => groups[name].Success)
.ToDictionary(name => name, name => groups[name].Value)
我只是在使用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());
基本上,您可以使用Select()
将每一行转换为EventLogLine
,然后使用GroupBy()
基于EventName创建分组,然后使用ToDictionary()
运行查询并以所需格式创建字典!
请参阅Match.Groups MSDN文章中的示例。 我认为您应该查看Alastair的答案,因为您输入的内容非常简单,如果您仅使用ReadLine和Split,则稍后阅读代码可能会更容易。
考虑使用ToLookup
而不是ToDictionary
。 通常,查找是不可变的,并且公开了一个非常简单的API,从而可以自然地与linq和通用代码一起工作。 另外,我会将解析封装到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]),
};
}
}
要回答问题的这一部分:
我没有看到任何公开组名称的与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");
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.