正则表达式 PHP。减少步数:受限于固定宽度 Lookbehind

Regex PHP. Reduce steps: limited by fixed width Lookbehind

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

我使用 lokarround 断言,让标点符号和白色 space 字符包围标签。
还有一个复杂的问题,有一种 bbcodes 代表 html.
我有两种类型的 bbcode,内联(^B 粗体 ^b)和块(^C 中心 ^c)。
必须通过内联字符才能到达上一个或下一个字符。 并且允许块包围标签,就像标点符号一样。

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

我怎样才能用更少的步骤更有效地做我的正则表达式?

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

(?<=[,\.:=\^ ]|\^[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