Python 100%CPU使用率,使用regexp,具体取决于输入长度

Python 100%CPU使用率,使用regexp,具体取决于输入长度,python,regex,cpu-usage,Python,Regex,Cpu Usage,我试图在Python中找到一个regexp,它必须匹配任何字符,但要避免三个或更多连续的逗号或分号。换句话说,最多只允许使用两个连续的逗号或分号 这就是我目前拥有的: ^(,|;){,2}([^,;]+(,|;){,2})*$ 它似乎如预期的那样起作用: >>> r.match('') <_sre.SRE_Match object at 0x7f23af8407e8> >>> r.match('foo,') <_sre.SRE_Match

我试图在Python中找到一个regexp,它必须匹配任何字符,但要避免三个或更多连续的逗号或分号。换句话说,最多只允许使用两个连续的逗号或分号

这就是我目前拥有的:

^(,|;){,2}([^,;]+(,|;){,2})*$
它似乎如预期的那样起作用:

>>> r.match('')
<_sre.SRE_Match object at 0x7f23af8407e8>
>>> r.match('foo,')
<_sre.SRE_Match object at 0x7f23af840750>
>>> r.match('foo, a')
<_sre.SRE_Match object at 0x7f23af8407e8>
>>> r.match('foo, ,')
<_sre.SRE_Match object at 0x7f23af840750>
>>> r.match('foo, ,,a')
<_sre.SRE_Match object at 0x7f23af8407e8>
>>> r.match('foo, ,,,')
>>> r.match('foo, ,,,;')
>>> r.match('foo, ,, ;;')
<_sre.SRE_Match object at 0x7f23af840750>
>>r.match(“”)
>>>r.match('foo',)
>>>r.match('foo,a')
>>>r.match('foo',)
>>>r.match('foo,,a')
>>>r.match('foo,,,')
>>>r.match('foo,,,,;')
>>>r.match('foo,,;;')
但是当我开始增加输入文本的长度时,regexp似乎需要更多的时间来给出响应

>>> r.match('foo, bar, baz,, foo')
<_sre.SRE_Match object at 0x7f23af8407e8>
>>> r.match('foo, bar, baz,, fooooo, baaaaar')
<_sre.SRE_Match object at 0x7f23af840750>
>>> r.match('foo, bar, baz,, fooooo, baaaaar,')
<_sre.SRE_Match object at 0x7f23af8407e8>
>>> r.match('foo, bar, baz,, fooooo, baaaaar,,')
<_sre.SRE_Match object at 0x7f23af840750>
>>> r.match('foo, bar, baz,, fooooo, baaaaar,,,')
>>> r.match('foo, bar, baz,, fooooo, baaaaar,,,,')
>>> r.match('foo, bar, baz,, fooooo, baaaaar, baaaaaaz,,,,')
r.match('foo,bar,baz,foo') >>>r.match('foo,bar,baz,,foooo,baaaar') >>>r.match('foo,bar,baz,,foooo,baaaar') >>>r.match('foo,bar,baz,,foooo,baaaar,,')) >>>r.match('foo,bar,baz,,foooo,baaaar,,,') >>>r.match('foo,bar,baz,,foooo,baaaar,,,,,,,) >>>r.match('foo,bar,baz,,foooo,baaaar,baaaaaz,,,,,) 最后,它在这个阶段完全停滞,CPU使用率上升到100%


我不确定是否可以优化regexp或是否涉及其他内容,希望您能提供帮助。

尝试以下正则表达式:

^([^,;]|,($|[^,]|,[^,])|;($|[^;]|;[^;]))*$
它重复匹配:

  • 既不是
    也不是
    的单个字符,或
  • 一个
    后面没有另一个
    ,或者一个
    后面没有另一个
    ,或者
  • a
    后接另一个
    或a
    后面没有另一个
直到到达终点。这是非常有效的,因为它在早期失败时没有进行太多的回溯。

您遇到的问题

这是因为您已将分隔符设置为可选的,因此正则表达式的
[^,;]+
部分(其本身在重复组中)将尝试大量置换(对于
baaaaaz
),最后在遇到两个以上的逗号时不得不承认失败

在正则表达式引擎执行1.000.000步后,中止与您的最后一个测试字符串的匹配尝试。Python将继续尝试

想象一下字符串
baaz,,,

尝试使用正则表达式时,正则表达式引擎必须检查所有这些:

  • baaz,,
  • baa
    +
    z,,
  • ba
    +
    az,,
  • ba
    +
    a
    +
    z,,
  • b
    +
    aaz,,
  • b
    +
    aa
    +
    z,,
  • b
    +
    a
    +
    az,
  • b
    +
    a
    +
    a
    +
    z,,
  • 在宣布全面失败之前。看看它是如何随着每个额外的字符呈指数增长的

    使用所有格量词或原子组可以避免这种行为,遗憾的是,Python当前的正则表达式引擎不支持这两种行为。但您可以轻松地进行反向检查:

    if ",,," in mystring or ";;;" in mystring:
        fail()
    

    根本不需要正则表达式。如果
    和类似的情况也可能发生,应该排除,然后使用Andrew的解决方案。

    我认为以下内容应该满足您的要求:

    ^(?!.*[,;]{3})
    
    如果字符串包含三个或三个以上的
    ,则此操作将失败在一行中。如果您确实希望它与字符匹配,请在末尾添加一个


    如果正则表达式
    *[,;]{3}
    匹配,则会导致整个匹配失败。

    这个想法如何匹配那些具有您不想要的模式的呢
    “+,”
    在Python中,只保留那些不匹配的。
    应该很快

    PyPI上的正则表达式实现不太容易出现这种问题。Thas是一个很好的解释,很高兴知道问题的根源。我想现在我将使用反向检查并放弃regexp。谢谢我以前尝试过环视操作员,但没有成功。您的解决方案足够简单和干净,当然也很有用,但我想我会使用@tim pietzcker的解决方案,并避免在这种特殊情况下使用regexp等以及
    如果alexis指出的是一个问题,您可以将正则表达式修改为
    ^(?。*(,,,;;)