C# 正则表达式性能问题
我有一个长字符串,其中包含大约100个参数(string parameterName),与以下模式匹配:C# 正则表达式性能问题,c#,regex,performance,C#,Regex,Performance,我有一个长字符串,其中包含大约100个参数(string parameterName),与以下模式匹配: parameterName + "(Whitespace | CarriageReturn | Tabulation | Period | Underline | Digit | Letter | QuotationMark | Slash)* DATA Whitespace Hexadecimal" 我曾尝试使用此正则表达式,但它的工作时间太长: parameterName + "[\\
parameterName + "(Whitespace | CarriageReturn | Tabulation | Period | Underline | Digit | Letter | QuotationMark | Slash)* DATA Whitespace Hexadecimal"
我曾尝试使用此正则表达式,但它的工作时间太长:
parameterName + "[\\s\\S]*DATA\\s0x[0-9A-F]{4,8}"
这个乱七八糟的比较好用:
parameterName + "(\\s|\r|\n|\t|\\.|[_0-9A-z]|\"|/)*DATA\\s0x[0-9A-F]{4,8}"
我会使用“*”,但是它与“\n”不匹配
我尝试过“(.|\n)”,但它的工作速度甚至比“[\s\s]”还要慢
有什么方法可以改进这个正则表达式吗?您可以使用
(?>(?>[^D]+|D(?!ATA))*)DATA\\s0x[0-9A-F]{4,8}
(?> # atomic grouping (no backtracking)
(?> # atomic grouping (no backtracking)
[^D]+ # anything but a D
| # or
D(?!ATA) # a D not followed by ATA
)* # zero or more time
)
想法
我们的想法是在不问自己任何问题的情况下获取数据,并且不要再进一步,然后返回到它
如果对字符串(如DATA321
)使用*DATA
,请参见正则表达式引擎的功能:
*
会吃掉所有字符串
- 找不到
数据
,因此引擎将逐步回溯并尝试以下组合:*
将只吃数据32
,然后是数据3
,然后是数据
。。。然后什么都没有,那就是我们找到对手的时候了
如果在123DATA
上使用*?DATA
:*?
将尝试不匹配任何内容,然后1
,然后12
每次尝试时,我们都必须检查停止位置之后是否没有数据
,这非常耗时。有了[^D]+|D(?!ATA)
我们可以确保在需要的时候停下来,而不是在之前,而不是之后
小心回溯
那么为什么不使用(?:[^D]| D(?!ATA))
而不是这些奇怪的原子分组呢
当我们找到匹配项时,这一切都很好,工作正常。但如果我们不这样做会发生什么呢?在声明失败之前,正则表达式必须尝试所有可能的组合。当您在每个字符上都有类似于(.*)*
的内容时,正则表达式引擎可以使用内部*
或外部
这意味着组合的数量很快变得巨大。我们不想尝试所有这些:我们知道我们停在了正确的地方,如果我们没有立即找到匹配的,我们永远不会。因此原子分组(显然.NET不支持所有格量词)
你可以理解我的意思:检查一个15个字符长的字符串需要8万个步骤,而这个字符串永远不会匹配
regex大师Friedl在这篇伟大的文章中对此进行了更深入的讨论(比我所能做的更好),您可以为SPEED.FYI编译您的regex,为了使通配符
匹配新行,您可以只使用s
标志。我会预编译我的regex,尽管我有每个的循环(parameterNameArray中的字符串parameterName),其中包含每个parameterName的正则表达式编译。感谢您的回答!但是,我尝试使用它时遇到了“嵌套量词异常”。嵌套量词确实会导致“灾难性回溯”,所以你必须使用所有格量词来避免这个问题。我猜C#module无法识别它,并且完全禁止它…只有通过删除++和*+才能解决这个问题。虽然我必须测试它,但它似乎工作得更快。无论如何,谢谢你!@Ivan:请不要这样做,它实际上相当“危险”。我马上解释原因。@Robin.NET不支持所有格量词。它将原始答案中的[^D]++
解释为([^D]+)+
;这就是导致“嵌套量词”异常的原因。