如何重构被SonarLint标记为易引发栈溢出的正则表达式?
问题描述
我有格式如下的CSV文件行:"A","B","C"
可以确定所有值均被双引号包裹,以逗号分隔。为解析出这些值,我使用了以下正则表达式:
var regex = ",(?=([^\"]*\"[^\"]*\")*[^\"]*$)"; var chunks = Stream.of(s.split(regex)) .map(e -> e.substring(1, e.length() - 1)) .toList();
执行后chunks列表会包含A、B、C三个值,目前运行正常。但SonarLint对此正则表达式发出警告:
Refactor this repetition that can lead to a stack overflow for large inputs
请问需要将该正则表达式修改为怎样的形式,才能避免栈溢出问题?
优化方案
方法1:优化正则表达式,消除回溯风险
原正则的嵌套重复结构([^\"]*\"[^\"]*\")*会让Java正则引擎产生大量递归回溯,处理长文本时容易触发栈溢出。可以用原子组(?>...)阻止回溯,优化后的正则如下:
var regex = ",(?=((?>[^\"]*\"){2})*[^\"]*$)";
原子组会锁定组内匹配的结果,不允许引擎回溯调整,大幅减少递归调用次数,避免栈溢出,同时保持原有的匹配逻辑(只匹配不在双引号内的逗号)。
方法2:换用更简单的字符串处理逻辑(推荐)
既然已经明确所有值都被双引号包裹,完全可以不用复杂正则,直接通过字符串截取+分割实现:
var chunks = Stream.of(s.substring(1, s.length() - 1).split("\",\"")) .toList();
先去掉字符串首尾的双引号,再按","分割,逻辑直观清晰,没有正则回溯的性能问题,不管输入多长都不会出现栈溢出,最终同样能得到A、B、C的结果。
内容的提问来源于stack exchange,提问作者Ch Ryder
相关产品推荐
相关产品推荐

