Java中正则匹配处理长字符串时出现StackOverflow问题
嘿,这个问题我太熟了!你遇到的StackOverflow是正则表达式里典型的灾难性回溯搞的鬼,咱们一步步拆解解决。
问题根源
你的正则模式简化后是\[((<[0-9a-fA-F]*>)*)\],核心问题出在嵌套的贪婪量词:内部的[0-9a-fA-F]*是贪婪匹配,外面又套了一个*来重复整个<...>单元。当处理长字符串时,尤其是字符串接近但不完全符合模式(比如末尾少个]),正则引擎会疯狂尝试所有可能的匹配组合,回溯次数呈指数级增长,直接把调用栈撑爆。短字符串因为回溯次数少,所以能正常运行。
优化方案
针对这个场景,我们可以通过两个关键调整彻底解决问题:
1. 用非捕获组减少内存开销
把原来的捕获组(...)改成非捕获组(?:...),因为你不需要保存每个<...>的匹配结果,非捕获组不会占用额外内存存储组匹配内容,能提升运行效率。
2. 用原子组阻止不必要的回溯
Java支持原子组(?>...),它的作用是:一旦原子组内的内容匹配成功,引擎就不会回溯这个组内的任何字符,直接跳过所有可能的回溯路径,从根本上避免灾难性回溯。
结合这两点,优化后的正则应该是:
static String shot = "\\[(?><[0-9a-fA-F]+>)*\\]";
另外,我把内部的[0-9a-fA-F]*改成了+——看你的示例都是带十六进制字符的<FFFD>格式,十六进制肯定至少有一个字符,这样能避免匹配空的<>,进一步减少无效匹配的可能。如果你的业务场景确实需要允许空的<>,再改回*就行。
效果验证
用你提供的长字符串测试优化后的正则,引擎会线性扫描字符串,不会产生大量回溯,不管字符串多长都能稳定运行,再也不会触发StackOverflow了。
内容的提问来源于stack exchange,提问作者Amrit Raj

