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个令牌如下:
它似乎适用于Java 1.6,但它不适用于Java 1.5。
自Java 1.4以来,正则表达式在Java中,为什么我会遇到这样的问题?
答案 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))
。重复直到后视镜中没有|
。它似乎为我在下面使用的测试用例产生了正确的结果。
因此,对于正则表达式,这是解决方法(假设原始正确):
"(?:^|(?<=,))(?:([^\",]+)|\"([^\"]*)\")(?:$|(?=,))"
为了防止前瞻问题,我还将其替换为非捕获组,因为结果对于您的用例保持不变。 (测试尚未揭示存在错误,但以防万一。)虽然我不完全确定,但我想我们可以信任引擎至少在(?<=,)
和(?=,)
上正常工作。我也冒昧地减少捕获组的数量,所以请重新计算它们。
<强>附录强>
使用输入字符串",abc,1234"
和正则表达式"(?<=^|[,.])"
和"(?<!^|[,.])"
进行测试。 JRE 1.5u18和JRE 1.6u32之间的结果不同。对于正面后视"(?<=^|[,.])"
,JRE 1.5u18的输出中缺少位置1的匹配,与JRE 1.6u32的输出相比。相反,对于JRE 1.5u18,位置1出现在负后瞻"(?<!^|[,.])"
的结果中,而JRE 1.6u32的输出不包含它。
看到这种互补行为并不令人意外,因为积极和消极的观察是完全相反的。
使用输入字符串",abc,."
和正则表达式"(?<=,abc|[,.])"
进行的另一项测试。位置1的匹配不会出现在JRE 1.5u18的结果列表中,与JRE 1.6u32相比。
如果我们交换周围的交替:"(?<=[,.]|,abc)"
,则JRE 1.5u18的结果中缺少位置4的匹配,与JRE 1.6u32相比。
可能不限于不同宽度,但我已经测试过。
我可以通过在交替中交换",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"