Java正则否定匹配行为差异:Java8与Java21结果为何不同?
Java 8与Java 21正则匹配结果差异的原因分析
问题现象
同样的正则匹配代码,在Java 8环境执行输出true,但在Java 21环境执行输出false,代码如下:
import java.util.regex.Matcher; import java.util.regex.Pattern; public class Main { public static void main(String[] args) { String regex = "^(/[^/[a-zA-Z0-9_.-]+]*)+/?$"; String inString = "/tmp"; // 类似/usr/pgsql-15这样的字符串结果一致 Matcher matcher = Pattern.compile(regex).matcher(inString); System.out.println("Matches regex: " + matcher.matches()); } }
差异原因
核心问题出在正则表达式的字符类写法错误,以及不同Java版本正则引擎的解析逻辑差异:
- 原正则中的
[^/[a-zA-Z0-9_.-]+]是错误的字符类定义。在Java 8中,正则引擎存在解析bug,错误地将字符类内部未转义的[当作普通字符处理,甚至错误识别字符类边界,导致这个字符类实际被解析为匹配除了/之外的任意字符——这使得/tmp中的tmp能被正常匹配,最终整个正则匹配成功。 - 在Java 21中,正则引擎的解析逻辑被修复,正确识别了字符类语法规则:
[^/[a-zA-Z0-9_.-]+]表示匹配除了/、[、字母、数字、_、.、-、+之外的单个字符。而tmp中的字符都属于被排除范围,因此[^/[a-zA-Z0-9_.-]+]*只能匹配空字符串,无法覆盖/tmp中的tmp部分,最终整个正则匹配失败。
与JDK-6609854的关联
这个差异确实和JDK-6609854直接相关。JDK-6609854正是针对正则表达式中字符类内部未转义[的解析错误进行的修复,Java 8受该bug影响,解析逻辑错误导致匹配结果不符合预期;Java 21已包含该修复,正则解析逻辑回归正确,因此匹配结果发生变化。
修正后的正则示例
如果你的意图是匹配类似/tmp、/usr/pgsql-15这类路径字符串,可使用以下正确的正则:
- 限定路径段只能包含字母、数字、下划线、点、横杠:
^(/[a-zA-Z0-9_.-]+)+/?$ - 允许路径段包含除
/之外的任意字符:^(/[^/]+)+/?$
内容的提问来源于stack exchange,提问作者powerful_clouds
相关产品推荐
相关产品推荐

