正则表达式匹配(\ w +)以捕获由|||分隔的单个单词 - Python

时间:2016-10-12 04:42:42

标签: python regex loops hang

我正在尝试匹配,如果有单词后跟\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())

1 个答案:

答案 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+个字符。