繁体   English   中英

使用python和javascript的慢正则表达式但在go和php中快速失败

[英]Slow regex with python and javascript but fast to fail in go and php

我写了一个正则表达式来解析PostgreSQL错误,试图向用户显示哪个字段有重复数据。 正则表达式是这样的:

^DETAIL:.[^\(]+.(.[^\)]+).[^\(]+.(.[^\)]+). already exists

如果你针对这样的正确消息( https://regex101.com/r/GZuREV/1 )运行它会非常快:

ERROR:  duplicate key value violates unique constraint "uq_content_block_internal_name_store_id"
DETAIL:  Key (lower(internal_name::text), store_id)=(some content block-32067683, 0c6d20a7-d843-44f3-af9c-4a2cf2a47e4c) already exists.

但是如果PostgreSQL发出如下所示的另一条消息,我的机器中需要大约30秒的python才能回答( https://regex101.com/r/GZuREV/2 )。

ERROR:  null value in column "active" violates not-null constraint
DETAIL:  Failing row contains (2018-08-16 14:23:52.214591+00, 2018-08-16 14:23:52.214591+00, null, 6f6d1bc9-c47e-46f8-b220-dae49bd58090, bf24d26e-4871-4335-9f18-83c5a52f1b3a, Some Product-a1c03dde-2de9-401c-92d5-5c1500908984, {"de_DE": "Fugit tempore voluptas quos est vitae.", "en_GB": "Qu..., {"de_DE": "Fuga reprehenderit nobis reprehenderit natus magni es..., {"de_DE": "Fuga provident dolorum. Corrupti sunt in tempore quae..., my-product-53077578, SKU-53075778, 600, 4300dc25-04e2-4193-94c0-8ee97b636739, 52553d24-6d1c-4ce6-89f9-4ad765599040, null, 38089c3c-423f-430c-b211-ab7a57dbcc13, 7d7dc30e-b06b-48b7-b674-26d4f705583b, null, {}, 0, null, 9980, 100, 1, 5).

如果转到regex101链接,你可以看到,如果你切换到不同的语言,如php或go,他们都返回很快说没有找到匹配,但如果你选择python或javascript你会得到超时。

我的快速脏修复是这样的:

match = 'already exists' in error_message and compiled_regex.search(error_message)

您认为这可能导致什么? 在达到我想要的数据之前,它可能是贪婪的操作员吗?

更新1

在python中使用re.IGNORECASE,因为它花费太多时间来降低某些东西,所以它会慢大约9秒。

用ignorecase

用ignorecase

没有忽视

没有忽视

更新2

在我周围玩耍时,我发现它可以使它工作并且失败,一个简单的改变就会破裂

^DETAIL:.[^\(]+?\((.[^\)]+?).[^\(]+?.(.[^\)]+?). already exists
                            ^ just changing this to \) make it stop timing out
^DETAIL:.[^\(]+?\((.[^\)]+?)\)[^\(]+?.(.[^\)]+?). already exists

包regexp

 import "regexp" 

包regexp实现正则表达式搜索。

接受的正则表达式的语法与Perl,Python和其他语言使用的通用语法相同。 更确切地说,它是RE2接受的语法,并在https://golang.org/s/re2syntax中描述,除了\\ C。 有关语法的概述,请运行

 go doc regexp/syntax 

此包提供的regexp实现保证在输入大小的时间线性运行。 (这是正则表达式的大多数开源实现无法保证的属性。)有关此属性的更多信息,请参阅

http://swtch.com/~rsc/regexp/regexp1.html

或任何关于自动机理论的书。


通过设计,Go正则表达式可以保证在输入的大小上按时间线性运行,这是正则表达式的其他一些实现无法保证的属性。 请参阅正则表达式匹配可以简单快速

TL; DR:使用此:

^DETAIL:\\s*+Key[^\\(]++\\((.+)\\)[^\\(]+\\(([^\\)]+)\\) already exists

请参阅匹配示例 匹配示例

解释:

首先,原始的regexp似乎与整个键组不匹配,你停在lower(internal_name::text ,省略了复合键的某些列以及不平衡的括号。如果你这样修改它应该有效捕获复合键。如果不应该这样做,请告诉我:

^DETAIL:.[^\\(]+.(.+)\\)[^\\(]+.(.[^\\)]+). already exists

只是改变这一点,正则表达式是“可运行的”,但仍然很慢。

其中一个主要原因是[^\\(]+ 。它首先匹配DETAIL: Failing row contains(space)并继续使用正则表达式的其余部分。它将不匹配,因此它回溯到少一个字符,最多DETAIL: Failing row contains并继续使用正则表达式的其余部分。它将不匹配,因此将返回到DETAIL: Failing row contain ...等。

避免这种情况的一种方法是使用占有量词。 这意味着一旦你拿到东西,你就不能回去了。 所以使用这个[^\\(]++代替这个[^\\(]+ (即: ^DETAIL:.[^\\(]++.(.+)\\)[^\\(]+.(.[^\\)]+). already exists )使正则表达式将步骤从28590减少到1290。

但你仍然可以改进它。 如果您知道所需数据使用关键字key ,请使用它! 这样,因为它在失败的示例中不存在,它将使正则表达式很快失败(一旦它读取DETAIL和下一个单词)

所以如果你使用^DETAIL:\\s*+Key[^\\(]++.(.+)\\)[^\\(]+.(.[^\\)]+). already exists ^DETAIL:\\s*+Key[^\\(]++.(.+)\\)[^\\(]+.(.[^\\)]+). already exists步骤现在只有12个。

如果你觉得使用key太具体了,你可以使用不太通用的东西试图找到“不'失败'”。 像这样:

^DETAIL:\\s*+(?!Fail)[^\\(]++.(.+)\\)[^\\(]+.(.[^\\)]+). already exists

这样就是17步。

最后,您可以调整匹配内容的正则表达式。

改变这个:

^DETAIL:\s*+Key[^\(]++.(.+)\)[^\(]+
.           # <============= here, use \( instead
(.[^\)]+). already exists

这样:

^DETAIL:\\s*+Key[^\\(]++.(.+)\\)[^\\(]+\\((.[^\\)]+). already exists

这样可以减少从538到215的步数,因为您可以减少回溯。

然后,在删除几个无用的点并用\\(\\) (个人品味)替换一些(假定为括号)点后,你有最终的正则表达式:

^DETAIL:\\s*+Key[^\\(]++\\((.+)\\)[^\\(]+\\(([^\\)]+)\\) already exists

这是一个正则表达式的怪物:)

为什么不拆分2个正则表达式?

  1. 检查是否already exists匹配(非常快)
  2. 使用现有正则表达式提取要显示的数据^DET.[^\\(]+.(.[^\\)]+).[^\\(]+.(.[^\\)]+)

这应该会加速你的代码。 (你甚至可以像我一样缩短细节)

这不是问题的答案,但我认为问题可能是贪婪的运营商。 无论如何,我认为你应该让它的某些部分懒得快速失败。

我使用了这种模式,它在regex101上的所有语言引擎上都可以:

^DETAIL:.+?\((.+)\).+?\((.+)\) already exists.

链接到匹配的错误

链接到没有匹配的错误

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM