解析大文件时避免使用正则表达式回溯

时间:2018-04-10 16:55:14

标签: c# regex .net-core backtracking

我正在解析一些符合模式的文件,以生成人类可读的报告。我使用正则表达式来解析这些文件。

文件示例:

2012-05-10 08:00:00.155: BROADCAST - Body: <?xml version="1.0" encoding="UTF-8" standalone="yes"?><Data></Data>. MessageProperties [headers={X_Day=20120510}]
2012-05-10 08:00:00.155: BROADCAST - Body: <?xml version="1.0" encoding="UTF-8" standalone="yes"?><Data></Data>. MessageProperties [headers={X_Day=20120510}]
2012-05-10 08:00:00.155: REQUEST - Body: <?xml version="1.0" encoding="utf-8"?>
<Data xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <field1>field1.val</field1>
  <field2>field2.val</field2>
</Data>. MessageProperties [headers={X_Day=20120510}, correlationId=[51, 56, 100, 54, 48, 48, 97, 54, 51, 99, 102, 100, 52, 102, 97, 51, 98, 51, 57, 52, 52, 49, 49, 50, 54, 97, 56, 100, 49, 48, 53, 98], other=blabla]

我想提取每个记录的时间部分,xml部分和属性部分。

正则表达式

目前我有这个正则表达式,它给了我想要的东西(我没有问题,如果可以帮助提高正则表达式的速度,可以在以后的处理中提取所需的确切位) :

((?:[0-9]{1,4}[-| |:|\.])+[0-9]{1,3}): .*Body: ((?:.|>\n|>\r|>\r\n)*\. MessageProperties )(\[.*\])

文件可能很大(如2000-10000匹配和100Mb),所以我想稍微优化一下。目前的问题是我所有的回溯。*在body之前和(?:。|&gt; \ n |&gt; \ r \ n)*之前的MessageProperties(我需要包含该行)明确地打破我给出的第三个示例记录。

有没有办法优化所有这些回溯?我无法找到方法。

我使用 regex101 进行开发,然后将其调整为 .Net

1 个答案:

答案 0 :(得分:2)

一般提示和改进

尽量避免单个字符替换,将部分量化到右侧而不是左侧部分,并尽可能使用字符类。使用unroll the loop principle可以更好地展开两个字符串之间的未知文本(即使您很想使用.*.*?)。

您的解决方案

您可以使用

^([0-9]{4}-[- :.0-9]*):\s+[^-]*\s+-\s+Body:\s+([^.]*(?:\.(?!\s+MessageProperties\s)[^.]*)*\.\s+MessageProperties\s+)(\[.*])

请参阅regex demo

<强>详情

  • ^ - 开始一行(与RegexOptions.Multiline选项一起使用,或者在模式前加(?m)时)
  • ([0-9]{4}-[- :.0-9]*) - 第1组:
    • [0-9]{4} - 4位数
    • - - 连字符
    • [- :.0-9]* - 0位数,.:-或空格字符 - :\s+[^-]*\s+-\s+ - :,1 +空格,除-以外的0 +字符,1 +空格,-,1 +空格
  • Body: - 子字符串
  • \s+ - 1+空格
  • ([^.]*(?:\.(?!\s+MessageProperties\s)[^.]*)*\.\s+MessageProperties\s+) - 第2组:
    • [^.]*(?:\.(?!\s+MessageProperties\s)[^.]*)* - 已展开的(?s:.*?).以外的任何0 +字符,后跟.的0 +序列,未跟随MessageProperties 1 +个空格,然后是.
    • 以外的任何0 +字符
    • \.\s+ - .和1 +空格
    • MessageProperties - 子字符串
    • \s+ - 1+空格
  • (\[.*]) - 第3组:[后跟除了换行符之外的任何0 +字符,然后是]