1

我有一个看起来像这样的日志文件:

2012-05-04 01:10:35;301383027;00133608663205759673480010256592;103;错误;摘要治疗:119;等等

废话2

废话3

2012-05-02 01:00:22;301382163;00133591322220336011720010256592;103;错误;摘要处理:119;blah4

废话5

废话6

2012-05-02 01:00:23;301382163;00133591322220336011720010256592;103;错误;摘要处理:119;等等

废话8

废话9

我想要 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]);[^;]*;[^;]*;[^;]*;([^;]*);(.*)

启用 Singleline 选项后,我有一个匹配项(整个输入),禁用此选项后,消息未完全捕获(仅与日期位于同一行的部分)。

我怎么能有与我想要正确捕获的 3 个值的日志条目一样多的匹配项?

编辑:我试图捕捉这样的比赛:

日期: 2012-05-04 01:10:35

严重性:错误

消息: AbstractTreatment:119;blah1

废话2

废话3

4

2 回答 2

5

这里有2个技巧。

  1. “。” 不包括“\n”,您不需要设置 RegexOptions.Multiline。

  2. 您需要使用另一个日期/时间模式或结束字符 ($) 作为分隔符,它们不应包含在匹配项中。(否则需要在搜索下一个匹配项之前从输入中排除分隔符)。
    这需要使用一个特殊的分组表达式,称为“零宽度正向预测断言”,其语法为 (?= 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
于 2012-05-12T01:26:11.293 回答
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 正则表达式中的交互方式很奇怪。

于 2012-05-12T03:50:49.873 回答