正则表达式不适用于java 1.5

时间:2013-01-19 12:34:33

标签: java regex jdk1.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
  4. 它似乎适用于Java 1.6,但它不适用于Java 1.5。

    自Java 1.4以来,正则表达式在Java中,为什么我会遇到这样的问题?

2 个答案:

答案 0 :(得分:5)

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

经过一些测试后,正面观察(?<=pattern)的实施以及负面观察(?<!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,"^来使问题中的正则表达式适用于此输入,,即将(?<=(^|,))更改为{{ 1}}。

答案 1 :(得分:1)

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"