我有一个如下所示的日志文件:
2012-05-04 01:10:35; 301383027; 00133608663205759673480010256592; 103; ERROR; AbstractTreatment:119; blah1
blah2
blah3
2012-05-02 01:00:22; 301382163; 00133591322220336011720010256592; 103; ERROR; AbstractTreatment:119; blah4
blah5
blah6
2012-05-02 01:00:23; 301382163; 00133591322220336011720010256592; 103; ERROR; AbstractTreatment:119; blah7
blah8
blah9
我希望每次有3个匹配的3个匹配组:日期,严重性和消息。
我试过使用这种模式
(20[0-9]{2}-[0-2][0-9]-[0-9]{2} [0-2][0-9]:[0-5][0-9]:[0-5][0-9]);[^;]*;[^;]*;[^;]*;([^;]*);(.*)
启用单行选项后,我有一个匹配(整个输入),如果禁用此选项,则不会完全捕获该消息(只有与日期在同一行的部分)。
我怎么能拥有与我想要正确捕获的3个值的日志条目一样多的匹配?
编辑: 我想捕捉这样的比赛:
日期: 2012-05-04 01:10:35
严重性:错误
消息: AbstractTreatment:119; blah1
blah2
blah3
答案 0 :(得分:5)
这里有两个技巧。
<强> “”不包括“\ n”,您无需设置 RegexOptions.Multiline。
您需要使用其他日期/时间模式或结束字符($)作为
分隔符,不应包含在匹配中。 (否则需要
在搜索之前从输入中排除分隔符
下一场比赛)。
这需要使用特殊的分组表达式
用语法称为“零宽度正向前瞻断言”
of(?= subexpression)。
要测试您的日志,我将其保存在“日志”设置变量中。
string log = Settings.Default.Log;
string datePattern = @"20[0-9]{2}-[0-2][0-9]-[0-9]{2} [0-2][0-9]:[0-5][0-9]:[0-5][0-9]";
string pattern = @"(?<date>" + datePattern + @");[^;]*;[^;]*;[^;]*;(?<severity>[^;]*);(?<message>(.|\n)*?)(?=(" + datePattern + @"|$))";
Match mtc = Regex.Match(log, pattern);
while (mtc.Success)
{
Console.WriteLine("Date: " + mtc.Groups["date"].Value);
Console.WriteLine("Severity: " + mtc.Groups["severity"].Value);
Console.WriteLine("Message: " + mtc.Groups["message"].Value);
mtc = mtc.NextMatch();
}
然后输出如下,
Date: 2012-05-04 01:10:35
Severity: ERROR
Message: AbstractTreatment:119;blah1
blah2
blah3
Date: 2012-05-02 01:00:22
Severity: ERROR
Message: AbstractTreatment:119;blah4
blah5
blah6
Date: 2012-05-02 01:00:23
Severity: ERROR
Message: AbstractTreatment:119;blah7
blah8
blah9
答案 1 :(得分:2)
Regex r = new Regex(
@"^(?<date>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2});[^;]*;[^;]*;[^;]*;(?<severity>[^;]*);(?<message>.*(\n+(?!\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2};)[^\n]+)*)",
RegexOptions.Multiline | RegexOptions.ExplicitCapture);
这个想法是,在.*
消耗第一行的剩余部分之后,\n+
消耗一个或多个行分隔符,而[^\n]+
消耗下一个非空行的内容 - - 但前提 - (?!\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2};)
- 无法匹配行开头的日期。 (因为,当然,以日期开头的行被假定为下一个日志条目的开头。)
Multiline
选项会导致^
锚点在换行符后以及字符串开头处匹配。 ExplicitCapture
表示只捕获命名组,因此我不必使用(?:...)
来阻止普通组捕获。每当使用命名组时,最好使用ExplicitCapture
;命名和编号组在.NET正则表达式中奇怪地交互。