我想在这里提交一个我想了解的非常具体的性能问题。
目标
我正在尝试使用正则表达式验证自定义合成器。通常,我不会遇到性能问题,所以我喜欢使用它。
箱
正则表达式:
^({[^][{}(),]+}s*([s*([([^][{}(),]+s*((s*([^][{}(),]+,?s*)+))?,?s*)+]s*){1,2}]s*)*)+$
有效的合成器:
{Section}[[actor1, actor2(syno1, syno2)][expr1,expr2]][[actor3,actor4(syno3, syno4)][expr3,expr4]]
你可以在这里找到正则表达式和测试文本: https://regexr.com/3jama
我希望这足够了,我不知道如何解释我想要匹配的东西而不是正则表达式;-)。
问题
在有效文本上应用正则表达式的成本并不高,几乎是即时的。 但是当涉及到特定的无效文本大小写时,正则表达式应用程序会挂起。它不是特定于正则表达式应用程序,因为我也遇到了我自己的java代码或javascript代码的戏剧性表演。
因此,我的需求是验证用户一直在键入文本。我什至可以想象在点击时验证文本,但如果用户提交的文本的结构如下,或者另一个产生相同的性能下降,我不能承受应用程序会挂起。
重现问题
只需从测试文本中删除尾随的"]"字符即可
因此,提高性能下降的无效文本变为:
{Section}[[actor1, actor2(syno1, syno2)][expr1,expr2]][[actor3,actor4(syno3, syno4)][expr3,expr4
另一个无效测试可能是,并且没有性能下降:
{Section}[[actor1, actor2(syno1, syno2)][expr1,expr2]][[actor3,actor4(syno3, syno4)][expr3,expr4]]]
请求
如果一个正则表达式大师可以解释我做错了什么,或者为什么我的用例不适合正则表达式,我会很高兴。
这个答案是针对您评论中的精简正则表达式:
^({[^][{}(),]+}([([([^][{}(),]+((([^][{}(),]+,?)+))?,?)+]){1,2}])*)+$
这些问题与您的原始模式类似。
你正面临着灾难性的回溯。每当正则表达式引擎无法完成匹配时,它就会回溯到字符串中,尝试找到其他方法将模式与某些子字符串匹配。如果你有很多模棱两可的模式,特别是如果它们发生在重复中,测试所有可能的变化需要很长时间。有关更好的解释,请参阅链接。
您使用的子模式之一是以下内容(多行线以获得更好的可视化):
([^][{}(),]+
((
([^][{}(),]+,?)+
))?
,?)+
这应该匹配像actor4(syno3, syno4)
这样的字符串。再压缩一下这个模式,你就可以([^][{}(),]+,?)+
了。如果你从中移除,?
,你会得到([^][{}(),]+)+
这是通向折返回退的打开门,因为字符串可以以许多不同的方式与这种模式匹配。
我明白你试图用这种模式做什么 - 匹配一个标识符 - 也许还有其他用逗号分隔的标识符。但是,执行此操作的正确方法是:([^][{}(),]+(?:,[^][{}(),]+)*)
.现在没有一种模棱两可的方法可以回溯到这种模式。
对上面显示的整个模式执行此操作(是的,必须推出另一个可选的逗号)并将其插入到您的完整模式中,我得到:
^({[^][{}(),]+}([([([^][{}(),]+((([^][{}(),]+(?:,[^][{}(),]+)*)))?(?:,[^][{}(),]+((([^][{}(),]+(?:,[^][{}(),]+))*))?)*)]){1,2}])*)+$
这不会再灾难性地回溯了。
您可能想帮自己一个忙,并将其拆分为子模式,您可以使用实际源中的字符串连接在一起,或者如果您使用的是 PCRE 模式,则使用 defined。
请注意,一些正则表达式引擎允许使用原子组和所有格量词,这进一步有助于避免不必要的回溯。由于您在标题中使用了不同的语言,因此您必须检查自己,哪一种语言可用于您选择的语言。