Tim*_*ido 6 regex negative-lookbehind negative-lookahead regex-lookarounds
我需要一个正则表达式,它只会选择那些不以 .png 或 .css 等特定扩展名结尾的 URL 字符串。
我测试了以下内容:
1)这个使用负回顾:
(?<!\.png|\.css)$
Run Code Online (Sandbox Code Playgroud)
https://regex101.com/r/tW4fO5/1
2)另一个使用负前瞻:
^(?!.*[.]png|.*[.]css$).*$
Run Code Online (Sandbox Code Playgroud)
https://regex101.com/r/qZ7vA4/1
两者似乎都工作正常,但据说 #1(负向后视)在 436 步(见链接)中处理,而 #2(负向后视)据说在 173 步中处理。
所以我的问题是:这是什么意思?会不会影响演出?
最后,这两个正则表达式在功能上真的是等价的吗?
编辑:解决方案摘要
总结一下,考虑到要通过正则表达式排除的字符串结尾的完整列表(一个典型的场景是 Web 服务器设置,其中静态资源由 apache 提供,而动态资源由不同的引擎提供 - 在我的情况下: php-fpm)。
PCRE 正则表达式有两种可能的选择:
1)负面回顾
$(?<!\.(?:ico|gif|jpg|png|css|rss|xml|htm|pdf|zip|txt|ttf)$|(?:js|gz)$|(?:html|woff)$)
https://regex101.com/r/eU9fI6/1
请注意,我使用了几个 OR ed 后视,因为负后视需要固定宽度的模式(即:您不能混合不同长度的模式)。这使得这个选项的编写稍微复杂一些。此外,在我看来,这降低了它的性能。
2)负前瞻
^(?!.*[.](?:js|ico|gif|jpg|png|css|rss|xml|htm|html|pdf|zip|gz|txt|ttf|woff)$).*$
https://regex101.com/r/dP7uD9/1
前瞻比后视略快。这是 100 万次迭代的测试结果:
后视时间 = 18.469825983047 秒
前瞻时间 = 14.316685199738 秒
如果我没有可变长度模式的问题,我会选择后视,因为它看起来更紧凑。反正哪一个都好。最后,我向前看:
<LocationMatch "^(?!.*[.](?:js|ico|gif|jpg|png|css|rss|xml|htm|html|pdf|zip|gz|txt|ttf|woff)$).*$">
SetHandler "proxy:unix:/var/run/php5-fpm.sock|fcgi://www/srv/www/gioplet/web/public/index.php"
</LocationMatch>
Run Code Online (Sandbox Code Playgroud)
会对演出产生影响吗?
在大多数情况下,正则表达式查找匹配项所需的步骤越多,性能就越慢。尽管这还取决于您稍后将在哪个平台上使用正则表达式(例如,如果您使用 regex101.com 测试在 .NET 中使用的正则表达式,但这并不意味着它将导致灾难性的回溯,惰性点匹配正则表达式会失败,并出现长文本)。
这两个正则表达式在功能上真的等效吗?
不,他们不是。查找前面没有或(?<!\.png|\.css)$的行尾。查找不包含或不以结尾的行。要使它们“等效”(也就是说,如果您想确保以或结尾的行不匹配),请使用.png.css^(?!.*[.]png|.*[.]css$).*$ .png .css.png.css
^(?!.*[.](?:png|css)$).*$
^^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)
确保在两者之后和否定前瞻中$检查。png css
正则表达式之间仍然存在差异:第一个仅匹配行尾,第二个将匹配整行。
有没有办法加快lookbehind解决方案的速度?
请注意,模式 1 中的lookbehind 会在字符串内的每个位置进行检查。模式 2 中的前瞻仅在字符串的开头检查一次。这就是为什么锚定前瞻解决方案在一种情况下会更快 - 如果您无法使用仅在少数正则表达式风格(例如.NET)中可用的 RightToLeft 修饰符。
后行$(?<!\.(?:png|css)$)解决方案比模式 1更快,因为后行模式在到达字符串/行末尾后仅检查一次。尽管如此,这仍然需要更多的步骤,因为后视的实现比前视的成本更高。
要真正找出哪种解决方案最快,您需要在您的环境中设置性能测试。