我正在尝试匹配,如果有单词后跟\s|||\s
,然后是另一个单词,后跟\s|||\s
,那么我正在使用此正则表达式:
single_word_regex = r'(\w+)+\s\|\|\|\s(\w+)\s\|\|\|\s.*'
当我尝试匹配此字符串时,正则表达式匹配会挂起或需要几分钟(可能会进入某种“深层循环”)
>>> import re
>>> import time
>>> single_word_regex = r'(\w+)+\s\|\|\|\s(\w+)\s\|\|\|\s.*'
>>> x = u'amornratchatchawansawangwong ||| amornratchatchawansawangwong . ||| 0.594819 0.5 0.594819 0.25 ||| 0-0 0-1 ||| 1 1 1 ||| |||'
>>> z = u'amor 我 ||| amor . i ||| 0.594819 0.0585231 0.594819 0.0489472 ||| 0-0 0-1 1-2 ||| 2 2 2 ||| |||'
>>> y = u'amor ||| amor ||| 0.396546 0.0833347 0.29741 0.08 ||| 0-0 0-1 ||| 3 4 2 ||| |||'
>>> re.match(single_word_regex, z, re.U)
>>> re.match(single_word_regex, y, re.U)
<_sre.SRE_Match object at 0x105b879c0>
>>> start = time.time(); re.match(single_word_regex, y, re.U); print time.time() - start
9.60826873779e-05
>>> start = time.time(); re.match(single_word_regex, x, re.U); print time.time() - start # It hangs...
为什么要花那么长时间?
是否有更好/更简单的正则表达式来捕获这种情况len(x.split(' ||| ')[0].split()) == 1 == len(x.split(' ||| ').split())
?
答案 0 :(得分:3)
请注意,r'(\w+)+'
模式本身不会导致catastrophic backtracking,它只会在较长的表达式中出现“邪恶”,特别是当它放在模式的开头旁边时如果后续的子模式失败,引擎会回溯到这个,并且内部的1+量词再次用+
量化,这会产生大量可能的变化,以便在失败之前尝试。您可以查看your regex demo并单击左侧的 regex调试器以查看示例正则表达式引擎行为。
当前的正则表达式可以写成
r'^(\w+)\s\|{3}\s(\w+)\s\|{3}\s(.*)'
如果删除空格,请参阅regex demo匹配的位置,并在第二个字段中找到.
。
<强>详情:
^
- 字符串的开头(不需要re.match
)(\w+)
- (第1组)1+字母/数字/下划线\s
- 空白\|{3}
- 3个管道符号\s(\w+)\s\|{3}\s
- 见上文((\w+)
创建第2组)(.*)
- (第3组)除了换行符之外的任何0+个字符。