Java 7、正则表达式和补充的Unicode字符

8

这个字符串有一个辅助unicode字符"\ud84c\udfb4"。根据javadoc,正则表达式匹配应该在代码点级别而不是字符级别上进行。然而,下面的分割代码将低代理项(\udfb4)视为非单词字符并在其上进行分割。

我错过了什么吗?有哪些其他替代方案可以实现在非单词字符上拆分?(Java版本“1.7.0_07”)

提前感谢。

Pattern non_word_regex = Pattern.compile("[\\W]", Pattern.UNICODE_CHARACTER_CLASS);
String a = "\u529f\u80fd\u0020\u7d76\ud84c\udfb4\u986f\u793a\u5ee3\u544a";
String b ="功能 絶顯示廣告";
System.out.print("original "+a+"\norginal hex ");
for(char c : a.toCharArray()){
    System.out.print(Integer.toHexString((int)c));
    System.out.print(' ');
}
System.out.println();

String[] tokens = non_word_regex.split(a);

for(int i =0; i< tokens.length; i++){
   String token = tokens[i];
   System.out.print(i+" ");
   for(char c : token.toCharArray()){
       System.out.print(Integer.toHexString((int)c));
       System.out.print(' ');
   }
   System.out.println();
}

输出:
原始 功能 绝显示广告
原始十六进制 529f 80fd 20 7d76 d84c dfb4 986f 793a 5ee3 544a
0 529f 80fd
1 7d76 d84c
2 986f 793a 5ee3 544a

1个回答

9

看起来这只是正则表达式引擎中的一个bug。如果使用\w表达式,所有内容都会正确匹配,但还剩下一个由两个字符组成的单一代码点。可以通过运行以下代码轻松验证:

Pattern pattern = Pattern.compile("(?U)[\\w]");
String str = "功能 絶顯示廣告";

Matcher matcher = pattern.matcher(str);
while (matcher.find()) {
    System.out.println(matcher.toMatchResult().group());
}

我刚刚进行了彻底的调查,所以我可以告诉您问题出在哪里。如果您查看java.util.regex.Pattern中的compile()方法(从第1625行开始),您将看到扫描正则表达式以决定是否支持补充字符扫描的代码。
这种方法的问题在于,该代码没有考虑到即使正则表达式没有补充字符,它仍然可能想要匹配它们,例如在您的情况下发生的情况。
解决方案是设计一些包含补充字符但不影响匹配过程的正则表达式。我建议您使用像这样的简单正则表达式: The solution is to devise some regex that contains the supplementary characters, but they don't affect the matching process. I suggest you use something innocent like this:

Pattern nonWordRegex = Pattern.compile("(?U)(?!\uDB80\uDC00)[\\W]");

这一部分(?!\uDB80\uDC00)起到了关键作用。它是一个负向前瞻,寻找补充字符的私有范围中的一个字符,这意味着在文本中很可能找不到它。然后正则表达式引擎认为模式中存在补充字符,并启用其支持!


很遗憾,Matcher不能保留单词边界。使用"[^\w]"进行预测,与"[\W]"得到相同的结果。我应该在Java论坛上发布吗? - user3088039
1
@user3088039 我刚刚解决了这个问题!请再次查看答案,我已经更新了它。 - Malcolm
你可能会认为"(?U)"会打开补充字符支持。感谢您的深入了解,它运行得非常好。 - user3088039

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接