Java 7,正则表达式和补充unicode字符

时间:2013-12-10 18:37:54

标签: java regex unicode supplementary

有问题的字符串有一个补充的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 个答案:

答案 0 :(得分:9)

这看起来就像正则表达式引擎中的一个错误。如果使用\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行开始),您将看到扫描正则表达式以获取补充字符的代码,并决定是否在扫描时支持它们。

这种方法的问题在于,代码没有考虑到这样一个事实,即即使正则表达式没有补充字符,它仍然可能想要匹配它们,例如在你的情况下。

解决方案是设计一些包含补充字符的正则​​表达式,但它们不会影响匹配过程。我建议你使用像这样无辜的东西:

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

部分(?!\uDB80\uDC00)可以解决问题。对于私人补充字符范围内的字符,这是一个负面的预测,这意味着很可能你不会在文本中找到它。瞧:正则表达式引擎认为模式中有补充字符,并开启他们的支持!