【发布时间】:2015-06-19 19:42:49
【问题描述】:
我已经阅读了 the articles 和 other questions 关于正则表达式中的灾难性回溯以及嵌套 + 和 * 量词如何导致它的内容。然而,我的正则表达式仍然遇到灾难性的回溯没有嵌套量词。有人可以帮我理解为什么吗?
我编写这些正则表达式是为了在威尔士诗歌中搜索a specific type of rhyme。押韵由行首的所有辅音在结尾重复组成,并且开头和结尾的辅音之间必须有一个空格。我已经删除了所有的元音,但是有两个例外使这些正则表达式变得丑陋。首先,允许中间有不重复的辅音,如果有,那就是另一种押韵。其次,字母 m、n、r、h 和 v 可以打断押韵(出现在开头而不出现在结尾,反之亦然),但它们不能被忽略,因为有时押韵只包含那些字母。
我的脚本会自动为每一行构建一个正则表达式并对其进行测试。它在其余时间都有效,但是这一行正在造成灾难性的回溯。该行没有元音的文本是:
nn Frvvn Frv v
正则表达式自动发现nn Frvvn 与Frv v 押韵,因此它会使用后面所需的最后一个字母(Frvvn 中的n)再次尝试。如果不需要,则可以缩短押韵。这是正则表达式:
^(?P<s_letters> # starting letters
[mnrhv]*?\s*n{0,2} # any number of optional letters or any number
# of spaces can come between rhyming letters
[mnrhv]*?\s*n{0,2}
[mnrhv]*?\s*F{1,2}
[mnrhv]*?\s*[rR]?(?:\s*[rR])? # r can also rhyme with R, but that's
# not relevant here (I think)
[mnrhv]*?\s*v{0,2}
[mnrhv]*?\s*v{0,2}
[mnrhv]*?\s*n{1,2}
[mnrhv\s]*?)
(?P<m_letters> # middle letters
[^\s]*?(?P<caesura>\s) # the caesura (end of the rhyme) is the
# first space after the rhyme
.*) # End letters come as late as possible
(?P<e_letters> # End group
[mnrhv]*?\s*n{0,2}
[mnrhv]*?\s*n{0,2}
[mnrhv]*?\s*F{1,2}
[mnrhv]*?\s*[rR]?(?:\s*[rR])?
[mnrhv]*?\s*v{0,2}
[mnrhv]*?\s*v{0,2}
[mnrhv]*?\s*n{1,2}
[mnrhv\s]*?)$
即使它没有任何嵌套的量词,它仍然需要很长时间才能运行。以相同方式生成的其他行的正则表达式运行得很快。这是为什么呢?
【问题讨论】:
-
Wayyy 对许多重叠的可选内容。您应该能够将其减少到几行。
-
有一个使用正则表达式的一般规则。任何可选的复合子表达式都应该包含非可选的内容。这有助于引擎对齐这些常数。它们被称为伪锚。最好的方法是将选项包含在一个集群组中,并通过交替将它们彼此分开。尝试隔离不同的表格并按照每个表格进行匹配。避免将可选的简单构造相互串联。
标签: python regex performance