我有一个长字符串,其中包含大约100个与以下模式匹配的参数(字符串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]”还慢。
有没有办法改善这个正则表达式?
答案 0 :(得分:1)
您可以使用类似
的内容(?>(?>[^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
)
想法
我的想法是在没有问自己任何问题的情况下到达DATA
,并且不再进一步,然后回溯到它。
如果对.*DATA
这样的字符串使用DATA321
,请查看正则表达式引擎的作用:
.*
吃掉所有字符串DATA
,因此引擎会一步一步地回溯并尝试这些组合:.*
只会吃DATA32
,然后DATA3
,然后{ {1}} ...然后没有,当我们找到匹配时就是这样。如果您在DATA
上使用.*?DATA
,则会发生同样的事情:123DATA
会尝试匹配任何内容,然后.*?
,然后1
...
在每次尝试时,我们都必须在12
停止的地方之后检查没有DATA
,这非常耗时。使用.*
,我们确保在需要时准确停止 - 而不是之前,而不是之后。
谨防回溯
那么为什么不使用[^D]+|D(?!ATA)
代替这些奇怪的原子分组?
当我们找到匹配项时,这一切都很好并且正常工作。但是当我们不这样做时会发生什么?在声明失败之前,正则表达式必须尝试所有可能的组合。当你在每个角色上都有(?:[^D]|D(?!ATA))
之类的东西时,正则表达式引擎可以使用内部(.*)*
或外部{。}}。
这意味着组合的数量非常迅速地变得巨大。我们希望不尝试所有这些:我们知道我们停在正确的地方,如果我们没有立即找到匹配,我们永远不会。因此原子分组(显然.NET不支持占有量词)。
你可以看到我的意思over here:80'000步检查一个永远无法匹配的15个字符的长字符串。
在这篇伟大的文章中,弗雷德尔,正则表达式大师,over here
进行了更深入的讨论(并且比我做的更好)