1
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. 美国广播公司

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

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

4

2 回答 2

5

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

(?<=pattern)经过一些测试,正面后视和负面后视(?<!pattern)1,2的实现存在一些错误。也许这与引擎在后视非捕获组内由交替分隔的不同宽度3时引擎如何回溯有关。|

在后视中交换项目的顺序有时有效4,但附录 2 显示它可能并非一直有效。

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

所以对于有问题的正则表达式,这是解决方法(假设原来的是正确的):

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

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

附录

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

    看到这种互补行为并不奇怪,因为正面和负面的后视是完全相反的。

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

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

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

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

于 2013-01-19T15:06:26.923 回答
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"
于 2013-01-19T12:43:08.063 回答