正则表达式不适用于java 1.5

public static final String PATTERN = "(?<=(^|,))(([^\",]+)|\"([^\"]*)\")(?=($|,))"; public static void main(String[] args) { String line = ",1234,ABC"; Matcher matcher = Pattern.compile(PATTERN).matcher(line); while (matcher.find()) { if (matcher.group(3) != null) { System.out.println(matcher.group(3)); } else { System.out.println(matcher.group(4)); } } } 

我使用上面的程序来解析字符串",1234,ABC" 。 解析后我应该获得3个令牌,如下所示:

  1. 空字符串即“”
  2. 1234
  3. ABC

它似乎适用于Java 1.6,但它不适用于Java 1.5。

从Java 1.4开始,正则表达式在java中,为什么我面临这样的问题呢?

这是Java类库中的一个错误(Sun的实现,由Oracle接管),至少在JRE 1.5 Update 18之前和JRE 1.6 Update 32之前(我测试过的2个版本)。

经过一些测试,在实施正面观察(?<=pattern)和负面观察(? 1,2时存在一些缺陷。 也许它与通过交替分离的图案的不同宽度3时发动机回溯的方式有关 ,在一个后瞻性的非捕获组内。

交换后视中项目的顺序有时会工作4 ,但附录2表明它可能不会一直工作。

就目前而言,似乎从后视中提取交替是一种可能的解决方案。 例如:具有交替的后视(?<=pat1|pat2|pat3)被转换为(?:(?<=pat1)|(?<=pat2)|(?<=pat3)) 。 重复直到没有| 在后面的内部。 它似乎为我下面使用的测试用例产生了正确的结果。

因此,对于正则表达式,这是解决方法(假设原始正确):

 "(?:^|(?<=,))(?:([^\",]+)|\"([^\"]*)\")(?:$|(?=,))" 

为了防止前瞻问题,我还将其替换为非捕获组,因为结果对于您的用例保持不变。 (测试尚未揭示存在错误,但以防万一。)虽然我不完全确定,但我想我们可以相信引擎至少可以正常工作(?<=,)(?=,) 。 我也冒昧地减少捕获组的数量,所以请重新计算它们。

附录

  1. 用输入字符串",abc,1234"和正则表达式"(?<=^|[,.])""(? 。 JRE 1.5u18和JRE 1.6u32之间的结果不同。 对于正面后"(?<=^|[,.])" ,JRE 1.5u18的输出中缺少位置1处的匹配,与JRE 1.6u32的输出相比。 相反,对于JRE 1.5u18,位置1出现在负面后卫"(? ,而JRE 1.6u32的输出不包含它。

    看到这种互补行为并不令人意外,因为积极和消极的后视是完全相反的。

  2. 另一个测试用输入字符串",abc,." 和正则表达式"(?<=,abc|[,.])" 。 位置1的匹配不会出现在JRE 1.5u18的结果列表中,与JRE 1.6u32相比。

    如果我们交换交替: "(?<=[,.]|,abc)" ,JRE 1.5u18的结果中缺少位置4的匹配,与JRE 1.6u32相比。

  3. 可能不限于不同的宽度,但我已经测试过的情况。

  4. 我可以使问题中的正则表达式适用于此输入",1234,ABC,\"sdfsdf,sdf\",sdfskhkf,"通过交换^并在交替中,即更改(?<=(^|,)) to (?<=(,|^))

 String line = ",1234,ABC"; String[]arr= line.split(","); System.out.println("arr.length = " + arr.length); for(String s : arr) { System.out.println("s = \"" + s+"\""); } 

输出是:

 arr.length = 3 s = "" s = "1234" s = "ABC"