为什么这个正则表达式需要这么长时间才能找到某些文件中的电子邮件地址?

T. *_*nes 7 php regex web-scraping

我有一个寻找电子邮件地址的正则表达式(这是从我找不到的另一个SO帖子中获取的,并且已经在各种电子邮件配置上进行了测试...更改这不是我的问题...但是要理解是否这是根本原因):

/[a-z0-9_\-\+]+@[a-z0-9\-]+\.([a-z]{2,3})(?:\.[a-z]{2})?/i
Run Code Online (Sandbox Code Playgroud)

我在PHP中使用preg_match_all().

这适用于99.99%的文件我正在查看并需要大约5毫秒,但有时需要几分钟.这些文件大于300k左右的平均网页,但更大的文件通常处理得很好.我能在文件内容中找到的唯一突出的是数千个连续的"随机"字母数字字符串,如下所示:

wEPDwUKMTk0ODI3Nzk5MQ9kFgICAw9kFgYCAQ8WAh4H...
Run Code Online (Sandbox Code Playgroud)

这是导致问题的两个页面.查看源以查看长字符串.

对这是什么造成的任何想法?

- 最终解决方案 -

我测试了答案中建议的各种正则表达式.@FailedDev的回答有助于将处理时间从几分钟缩短到几秒钟.@hakre的答案解决了问题并将处理时间缩短到几百毫秒.以下是我使用的最终正则表达式.这是@hakre的第二个建议.

/[a-z0-9_\-\+]{1,256}+@[a-z0-9\-]{1,256}+\.([a-z]{2,3})(?:\.[a-z]{2})?/i
Run Code Online (Sandbox Code Playgroud)

hak*_*kre 8

您已经知道正则表达式导致大文件出现问题.那么也许你可以让它变得更聪明一些?

例如,您正在使用+匹配一个或多个字符.假设你有一串10 000个字符.正则表达式必须看10000个组合才能找到最大的匹配.然后你将它与类似的结合起来.假设你有一个包含20 000个字符和两个字符串的字符串+.他们怎么能在文件中匹配.可能是10 000 x 10 000种可能性.等等等等.

如果你能限制(这看起来有点像你正在寻找电子邮件模式)的字符数,可能限制电子邮件地址的域名为256和地址本身为256个字符.那么这将是"仅"测试的256 x 256种可能性:

/[a-z0-9_\-\+]{1,256}@[a-z0-9\-]{1,256}\.([a-z]{2,3})(?:\.[a-z]{2})?/i
Run Code Online (Sandbox Code Playgroud)

这可能已经快得多了.然后使这些量词占有率将减少PCRE的回溯:

/[a-z0-9_\-\+]{1,256}+@[a-z0-9\-]{1,256}+\.([a-z]{2,3})(?:\.[a-z]{2})?/i
Run Code Online (Sandbox Code Playgroud)

哪个应该再加快速度.


Fai*_*Dev 6

我最好的猜测是尝试使用积极的量词:

[a-z0-9_\-\+]+
Run Code Online (Sandbox Code Playgroud)

[a-z0-9_\-\+]++
Run Code Online (Sandbox Code Playgroud)

这应该会使正则表达式更快失败,因此可以在这些情况下提高性能.

编辑:

也许原子分组也可以帮助:

/(?>[a-z0-9_\-+]++)@(?>[a-z0-9\-]++\.)(?>[a-z]{2,3})(?:\.[a-z]{2})?/
Run Code Online (Sandbox Code Playgroud)

你应该先选择一个.通过使用选项2看看是否存在任何差异将会很有趣.