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

use*_*039 8 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();
}
Run Code Online (Sandbox Code Playgroud)

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

Mal*_*olm 9

这看起来就像正则表达式引擎中的一个错误.如果使用\w表达式,一切都正确匹配,仍然是由两个字符组成的单个代码点.通过运行以下代码可以轻松验证这一点:

Pattern pattern = Pattern.compile("(?U)[\\w]");
String str = "?? ?????";

Matcher matcher = pattern.matcher(str);
while (matcher.find()) {
    System.out.println(matcher.toMatchResult().group());
}
Run Code Online (Sandbox Code Playgroud)

我刚刚进行了调查,所以我可以告诉你问题出在哪里.如果你看一下该方法compile()java.util.regex.Pattern中,你会发现扫描增补字符正则表达式,并决定是否要支持他们在扫描或不代码(上线1625开始).

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

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

Pattern nonWordRegex = Pattern.compile("(?U)(?!\uDB80\uDC00)[\\W]");
Run Code Online (Sandbox Code Playgroud)

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