使用python和javascript的正则表达式速度慢,但在go和php中很快就会失败
我编写了一个正则表达式来解析PostgreSQL错误,试图向用户显示哪个字段有重复的数据。 正则表达式是这样的:使用python和javascript的正则表达式速度慢,但在go和php中很快就会失败,javascript,python,regex,go,Javascript,Python,Regex,Go,我编写了一个正则表达式来解析PostgreSQL错误,试图向用户显示哪个字段有重复的数据。 正则表达式是这样的: ^DETAIL:.[^\(]+.(.[^\)]+).[^\(]+.(.[^\)]+). already exists 如果您针对这样的正确消息运行它,它将非常快(): 但是,如果PostgreSQL发出另一条类似于以下消息的消息,那么python在我的机器上大约需要30秒才能回答() 如果转到regex101链接,您可以看到,如果切换到不同的语言,如php或go,它们都会很快返回,
^DETAIL:.[^\(]+.(.[^\)]+).[^\(]+.(.[^\)]+). already exists
如果您针对这样的正确消息运行它,它将非常快():
但是,如果PostgreSQL发出另一条类似于以下消息的消息,那么python在我的机器上大约需要30秒才能回答()
如果转到regex101链接,您可以看到,如果切换到不同的语言,如php或go,它们都会很快返回,表示未找到匹配项,但如果选择python或javascript,则会出现超时
我的快速修复是这样的:
match = 'already exists' in error_message and compiled_regex.search(error_message)
你认为是什么原因造成的?在我获得所需数据之前,可能是贪婪的运营商在消费吗
更新1
在python中使用re.IGNORECASE会使它慢9秒左右,因为它花费了太多的时间来小写
无知的
无故
更新2
玩游戏时,我看到,要让它工作起来,但失败了,一个简单的改变就会失败
^DETAIL:.[^\(]+?\((.[^\)]+?).[^\(]+?.(.[^\)]+?). already exists
^ just changing this to \) make it stop timing out
^DETAIL:.[^\(]+?\((.[^\)]+?)\)[^\(]+?.(.[^\)]+?). already exists
这是一个正则表达式怪物:)
为什么不拆分这两个正则表达式呢
是否已存在
是否匹配(非常快)^DET.[^\([^\]+。([^\]+).[^\(]+。([^\)]+).[^\]+)
go doc regexp/syntax
此包提供的regexp实现保证
输入的大小与运行时间呈线性关系。(这是一处不属于
由大多数常规的开源实现保证
表达式。)有关此属性的详细信息,请参阅
或者任何关于自动机理论的书
通过设计,Go正则表达式可以保证在输入大小为线性的时间内运行,这是正则表达式的一些其他实现无法保证的特性。请看。这不是问题的真正答案,但我认为问题可能在于贪婪的运算符。不管怎样,我认为你应该让它的一部分懒散地快速失败 我使用了这种模式,在regex101上的所有语言引擎上都可以:
^DETAIL:.+?\((.+)\).+?\((.+)\) already exists.
TL;DR:使用以下方法:
^详细信息:\s*+键[^\(]+\(.+)\)[^\(]+\([^\)]+\)已存在
看到和
解释:
首先,原始regexp似乎与整个键组不匹配,您在下(internal_name::text
)停止,遗漏了复合键的一些列以及不平衡的括号。如果您这样修改它,应该可以捕获复合键。如果不应该这样做,请告诉我:
^详细信息:.[^\(]+。(.+)\)[^\(]+。(.[^\)]+)。已存在
仅仅通过改变这一点,正则表达式是“可运行的”,但仍然相当缓慢
主要原因之一是[^\(]+
。它首先匹配到详细信息:失败的行包含(空格)
并与正则表达式的其余部分继续。它将不匹配,因此它将回溯到少一个字符,直到详细信息:失败的行包含
,并继续与正则表达式的其余部分匹配。它将不匹配,因此将返回到详细信息:失败的行包含
…等
避免这种情况的一种方法是使用所有格量词。这意味着一旦你取了东西,你就不能再回去了。因此,使用这个[^”(]++
而不是这个[^”(]++
(也就是说:^DETAIL:.[^(.+)[^+.[^+.[^+.]+.[^+.]已经存在的)可以使regexp的步数从28590减少到1290
但是您仍然可以改进它。如果您知道所需的数据使用关键字key
,请使用它!这样,由于失败的示例中没有该关键字,它将使正则表达式很快失败(一旦它读取了详细信息和下一个单词)
因此,如果使用^详细信息:\s*+键[^\(]+.(.+)\)[^\(]+.[^\]+)。已经存在的步骤现在只有12个
如果您觉得使用键
过于具体,可以使用一些不太通用的方法来查找“not'Fail'”。如下所示:
^详细信息:\s*+(?!Fail)[^\(]+。(.+)\)[^\(]+。(..[^\)]+)。已存在
这样走17步
最后,您可以针对匹配的内容调整正则表达式
更改此项:
^DETAIL:\s*+Key[^\(]++.(.+)\)[^\(]+
. # <============= here, use \( instead
(.[^\)]+). already exists
^详细信息:\s*+键[^\(]+.(.+)\)[^\(]+
.#如果我删除首字母^或使用多行,看起来速度会非常慢。这一个很好,我忘记了+?可能会使它变慢,谢谢!
go doc regexp/syntax
^DETAIL:.+?\((.+)\).+?\((.+)\) already exists.
^DETAIL:\s*+Key[^\(]++.(.+)\)[^\(]+
. # <============= here, use \( instead
(.[^\)]+). already exists