SonarLint提示正则重复易致栈溢出,求匹配至少6个数字的优化正则
解决方案
正则表达式优化方案
原正则的问题在于嵌套的贪婪重复结构会引发大量回溯,SonarLint的警告正是针对这种潜在的栈溢出风险。优化后的正则可以避免过度回溯,同时满足需求:
String patternString = "^(?=(?:.*?\\d){6}).*$";
正则说明
^(?=(?:.*?\\d){6}):正向预查,确保字符串中至少包含6个数字。.*?是非贪婪匹配任意字符,会尽快定位到下一个数字,大幅减少回溯次数;(?:...)是非捕获组,避免不必要的内存开销。.*$:匹配整个字符串,符合matches()方法要求全串匹配的规则。
更高效的非正则替代方案
如果追求极致性能(尤其是处理大文本时),直接遍历字符串统计数字数量是更优的选择,完全规避正则引擎的回溯问题:
public static boolean hasAtLeastSixDigits(String s) { int digitCount = 0; for (char c : s.toCharArray()) { if (Character.isDigit(c)) { digitCount++; if (digitCount >= 6) { return true; } } } return false; }
修改后的测试代码
使用优化后的正则:
import java.util.regex.Pattern; import java.util.regex.Matcher; public class MyClass { public static void main(String[] args) { String[] strings = { "JamesBond1.zip", "JamesBond 1 2 3456.zip", "JaneBond X 3-4-2024"}; String patternString = "^(?=(?:.*?\\d){6}).*$"; Pattern pattern = Pattern.compile(patternString); for (String s : strings) { Matcher matcher = pattern.matcher(s); if (matcher.matches()) { System.out.println("\"" + s + "\" matches the pattern."); } else { System.out.println("\"" + s + "\" does not match the pattern."); } } } }
使用非正则方法:
public class MyClass { public static void main(String[] args) { String[] strings = { "JamesBond1.zip", "JamesBond 1 2 3456.zip", "JaneBond X 3-4-2024"}; for (String s : strings) { if (hasAtLeastSixDigits(s)) { System.out.println("\"" + s + "\" matches the pattern."); } else { System.out.println("\"" + s + "\" does not match the pattern."); } } } public static boolean hasAtLeastSixDigits(String s) { int digitCount = 0; for (char c : s.toCharArray()) { if (Character.isDigit(c)) { digitCount++; if (digitCount >= 6) { return true; } } } return false; } }
两种方案都能满足预期:第一个字符串不匹配,后两个匹配,同时消除SonarLint的警告。
内容的提问来源于stack exchange,提问作者gcpd0711
相关产品推荐
相关产品推荐

