灾难性回溯搜索括号中的数字

Posted

技术标签:

【中文标题】灾难性回溯搜索括号中的数字【英文标题】:Catastrophic backtracking searching for numbers in brackets 【发布时间】:2021-06-18 08:05:41 【问题描述】:

使用这个正则表达式:\((\W*\d*\W*)*\) 我正在寻找括号内的数字。这些数字可以被任何符号包围,但不能被字符包围,并且这种模式可以在括号内出现很多次,我的意思是我需要在这里匹配所有内容:

(8) (8,) (8'') (8, 9, 8 ,9) (18, 9', 89;) ('7;27;37.38;48;55)

但不是:

(8j) (a888) (1, 2; 12.13; 25.26; 35.36; 43.45; 52.56; 59,6o)

最后一个例子给了我一个灾难性的回溯错误。我怎样才能避免这个错误?我真的不明白该怎么做......

【问题讨论】:

如果您总是期望至少一位数字,那么您不应该在\d 之后以及捕获组之后使用* 量词。请改用+ 你可以用下面的(?:\(|\G(?!^))[^a-z\n\)]*?\K\d+(?:\.\d+)?(?=[^a-z\n\)]*\)) @silkfire (\W*\d+\W*)+ 仍然有灾难性的回溯,因为两个相邻的\W* 在一个组重复中(通过使用(\W*\d+)+\W* 来解决这个问题),并且\W* 可能不匹配任何相邻的东西数字可能是外部组的重复(通过使用(\W*\d)+\W*\W*\d+(\W+\d+)*\W* 修复)。 【参考方案1】:

您可以将您的正则表达式更改为 \([\W\d]*\),这将匹配和不匹配您的示例。

见https://regex101.com/r/DNmuEb/1/

【讨论】:

我认为这是最好和更清洁的解决方案。谢谢。【参考方案2】:

\((\W*\d*\W*)*\) 的灾难性回溯是由于嵌套的可选量词造成的,一切都是可选的。

注意\W也可以匹配()

您可以匹配除字符 A-Z a-z 或括号之外的任何空白字符,如果您需要匹配所有内容,则在括号之间至少声明一个数字

\((?=[^()\d]*\d)[^A-Za-z()]+\)
\( 匹配( (?=[^()\d]*\d) 在括号之间至少声明一个数字 [^A-Za-z()]+ 匹配除字符 A-Z a-z ( ) 以外的任何字符的 1+ 倍,如果您想扩展它,可以添加更多 \)匹配)

Regex demo

【讨论】:

以上是关于灾难性回溯搜索括号中的数字的主要内容,如果未能解决你的问题,请参考以下文章

如何避免使用这种特定模式的灾难性回溯

这个正则表达式不应该发生灾难性的回溯

正则表达式模式灾难性回溯

如何彻底避免正则表达式的灾难性回溯?

Go 正则表达式中没有灾难性的回溯吗?

如何使这个正则表达式不会导致“灾难性回溯”?