regex 如何编写下面的正则表达式而不发生灾难性回溯

fsi0uk1n  于 2023-03-31  发布在  其他
关注(0)|答案(2)|浏览(87)

我尝试在javascript中使用正则表达式,输入元素中不允许使用特殊字符和前导和尾随空格。最大字符长度为50。
我使用的正则表达式是

/^[a-zA-Z0-9]+([ ]?[a-zA-Z0-9]+)*$/

但是当字符串很大并且末尾有一个特殊字符时,这会导致问题。在研究中,我发现这是由于灾难性的回溯而发生的,但我无法优化正则表达式。请帮助我找到这个问题的最佳解决方案。
我尝试去抖动输入元素的keyup事件,但这也没有解决问题。

kb5ga3dv

kb5ga3dv1#

这就像从空格后面删除可选的量词(?)一样简单:
/^[a-zA-Z0-9]+([ ][a-zA-Z0-9]+)*$/应该没问题。
我们需要论证两件事:
1.* 这不会改变RegEx匹配的内容 :可选的量词是不必要的。Kleene星星(*)已经使整个空格分隔的部分(([ ][a-zA-Z0-9]+))成为可选的。如果没有空格,您将只有字母数字,[a-zA-Z0-9]+将匹配。
1.
这将彻底改变运行时 *:一个字符要么是一个空格,要么匹配[a-zA-Z0-9]。RegEx引擎只能进入一种状态:如果是字母数字,则必须留在贪婪量词中;如果它是一个空格,它必须前进,然后期望至少一个字母数字。特别是,什么不能再发生的是,RegEx引擎有 * 两个选项 *:是进入Kleene星星的另一次迭代还是停留在当前的[a-zA-Z0-9]+
我还做了一些修改,将Kleene星星移到前面,并使用i标志来进一步缩短它(然后可以省略A-Z)。空格周围的[]括号也是不必要的。使用第四只鸟的测试,它是如何执行的:/^([a-z0-9]+ )*[a-z0-9]+$/i .
像你当前的RegEx一样,这并不强制执行长度要求。我建议在针对RegEx进行测试之前在JavaScript中强制执行长度要求。这将是最易读和最有效的。

d8tt03nd

d8tt03nd2#

您可以从匹配单个字符的模式开始,以防止在每一行上触发lookahead,然后Assert0-49个字符。
然后将模式添加到lookahead中的捕获组中,然后使用对组1的反向引用来匹配字符串,因为lookahead是原子的。
/i使用不区分大小写的模式

^[a-z0-9](?=[a-z0-9 ]{0,49}$)(?=([a-z0-9]+(?: [a-z0-9]+)*))\1$

参见regex demo

相关问题