Pattern p = Pattern.compile("^(?>[a-z]+)+(?<!-)$");
// 或使用占有量词
Pattern p2 = Pattern.compile("^[a-z]++$");
System.out.println(p2.matcher(input).matches());
校验一段很长的用户输入时抛栈溢出,短文本却正常,规则里嵌套了多个可选分组。先别急着动参数,把报错原文和时间点记下来,顺序反了容易白折腾。
原因不复杂,嵌套量词导致回溯次数指数级增长,递归深度超过线程栈上限。
「Java 正则回溯」改完先别急着全量,挑一台机器放半天,真有问题这段时间就能看出来。改完隔一天再看一次,当场正常不代表能稳住。
测试环境和线上的差别,往往就在版本号和那几行被忽略的配置上。线上出问题先对时间点,跟发布、备份、任务执行的时刻排一排,能省掉一半功夫。
日志级别临时调高可以,记得改回去,长期开着既占磁盘又掩盖真问题。权限不要一口气开到最大,先加到够用再往上试,范围小才好收。
处理上按这个顺序:改写为占有量词或原子组;拆分复杂规则分步校验;对超长输入先做长度限制。
改完只确认一件事:同样的长输入能快速返回结果,不再抛栈溢出错误。