[英]100% CPU usage with a regexp depending on input length
我试图在 Python 中提出一个正则表达式,它必须匹配任何字符,但要避免三个或更多连续的逗号或分号。 换句话说,最多只能使用两个连续的逗号或分号。
所以这就是我目前拥有的:
^(,|;){,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('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,,,,')
最后它在这个阶段完全卡住了,CPU 使用率上升到 100%。
我不确定是否可以优化正则表达式或是否涉及其他内容,感谢任何帮助。
你遇到了灾难性的回溯。
这样做的原因是您已将分隔符设为可选,因此您的正则表达式的[^,;]+
部分(它本身在重复组中)将在最终不得不承认失败之前尝试( baaaaaaaz
)的大量排列当遇到两个以上的逗号时。
RegexBuddy在正则表达式引擎的 1.000.000 步后使用您的最后一个测试字符串中止匹配尝试。 Python 会继续努力。
想象一下字符串baaz,,,
:
尝试您的正则表达式,正则表达式引擎必须检查所有这些:
baaz,,<failure>
baa
+ z,,<failure>
ba
+ az,,<failure>
ba
+ a
+ z,,<failure>
b
+ aaz,,<failure>
b
+ aa
+ z,,<failure>
b
+ a
+ az,,<failure>
b
+ a
+ a
+ z,,<failure>
在宣布全面失败之前。 看看这如何随着每个额外的字符呈指数增长?
使用所有格量词或原子组可以避免此类行为,遗憾的是 Python 当前的正则表达式引擎不支持这两种行为。 但是您可以轻松地进行反向检查:
if ",,," in mystring or ";;;" in mystring:
fail()
根本不需要正则表达式。 如果,;,
和类似的情况也可能发生并且应该被排除,那么使用 Andrew 的解决方案。
我认为以下应该做你想要的:
^(?!.*[,;]{3})
如果字符串包含三个或更多,这将失败,
或者;
连续。 如果您确实希望它匹配一个字符,请添加一个.
在最后。
这利用了负前瞻,如果正则表达式.*[,;]{3}
匹配,这将导致整个匹配失败。
试试这个正则表达式:
^([^,;]|,($|[^,]|,[^,])|;($|[^;]|;[^;]))*$
它重复匹配:
,
也不是的单个字符;
, 或者,
后面没有另一个,
或 a ,,
后面没有另一个,
, 或;
要么没有跟随另一个;
或一个;;
后面没有另一个;
直到到达终点。 它非常有效,因为它会提前失败而无需进行太多回溯。
这个想法如何匹配那些你不想要的模式".+,,,"
在 Python 中只保留那些不匹配的。 应该快
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.