我有一个正则表达式,将用于匹配@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])
最佳答案
经验法则:
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
标志而不是定义大写形式的字母(但这可能会产生一点影响)。
关于php - 正则表达式 PHP。减少步骤: limited by fixed width Lookbehind,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54074550/