php - 正则表达式 PHP。减少步骤: limited by fixed width Lookbehind

标签 php regex regex-lookarounds lookbehind

我有一个正则表达式,将用于匹配@users标签。

我使用 lokarround 断言,让标点符号和空格字符包围标签。
还有一个额外的复杂性,有一种代表 html 的 bbcode。
我有两种类型的 bbcode,内联(^B 粗体 ^b)和 block (^C center ^c >).
必须传递内联字符才能到达上一个或下一个字符。 并且这些 block 可以包围标签,就像标点符号一样。

我制作了一个有效的正则表达式。我现在想做的是减少它在每个不匹配的字符中执行的步骤数。
起初我以为我可以做一个只查找 @ 的正则表达式,当找到时,它会开始查看lookarrounds,它可以在没有内联 bbcodes 的情况下工作,但由于lookbehind 无法量化,所以它是更困难,因为我无法在内部添加 ((\^[BIUbiu])++)* ,从而产生更多步骤。

如何以更少的步骤更高效地执行正则表达式?

这是它的简化版本,在 Regex101 链接中有完整的正则表达式。

(?<=[,\.:=\^ ]|\^[CJLcjl])((\^[BIUbiu])++)*@([A-Za-z0-9\-_]{2,25})((\^[BIUbiu])++)*(?=[,\.:=\^ ]|\^[CJLcjl])

https://regex101.com/r/lTPUOf/4/

最佳答案

经验法则:

Do not let engine make an attempt on matching each single one character if there are some boundaries.

这句话最初来自这个答案。由于最外层交替的左侧,遵循正则表达式可以显着减少步骤,从 ~20000 到 ~900:

(?:[^@^]++|[@^]{2,}+)(*SKIP)(*F)
|
(?<=([HUGE-CHARACTER-CLASS])|\^[cjleqrd])
    (\^[34biu78])*+@([a-z\d][\w-.]{0,25}[a-z\d])(\^[34biu78])*+(?=(?1))

实际上,我不太关心 regex101 报告的步骤数,因为在您自己的环境中这不是真的,并且某些步骤是否真实或遗漏了哪些步骤并不明显。但在这种情况下,由于正则表达式的逻辑很清晰,并且差异很大,所以这是有道理的。

逻辑是什么?

我们首先尝试匹配可能根本不需要的东西,将其扔掉并寻找可能与我们的模式匹配的部分。 [^@^]++ 最多匹配 @^ 符号(所需字符)和 [@^]{2 ,}+ 防止引擎在发现它毫无进展之前采取额外的步骤。所以我们尽快让它失败。

您可以使用 i 标志而不是定义大写形式的字母(但这可能会产生一点影响)。

参见live demo here

关于php - 正则表达式 PHP。减少步骤: limited by fixed width Lookbehind,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54074550/

相关文章:

regex - 在 xml 架构 (xsd) 上嵌入正则表达式(电话号码验证)时出错

带有特殊字符的正则表达式环视无效?

javascript - 如何将 php session 转换为可用变量

php - 如果在键盘上按下名字的第一个字母,则滚动到网页上的人名

regex - 如何使用正则表达式找到空白的 Markdown 标题?

regex - R 在除特定单词外的所有单词周围放置引号

java - 如何获取模式 : regex not followed by another regex 的不匹配项

php - 我正在寻找一种安全地将字符串插入数据库的方法?

php - symfony2实体的slugify方法在哪里

regex - Perl 脚本将两个模式之间的行合并为一行并打印整个文件