Java 7, регулярные выражения и дополнительные символы Юникода
Рассматриваемая строка имеет дополнительный символ 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 ответ
Это выглядит просто как ошибка в движке регулярных выражений. Если вы используете \w
выражение, все соответствует правильно, остается единой кодовой точкой, состоящей из двух символов. Это легко проверить, выполнив следующий код:
Pattern pattern = Pattern.compile("(?U)[\\w]");
String str = "功能 絶顯示廣告";
Matcher matcher = pattern.matcher(str);
while (matcher.find()) {
System.out.println(matcher.toMatchResult().group());
}
Я только что провел тщательное расследование, и поэтому могу сказать вам, где проблема. Если вы посмотрите на метод compile()
в java.util.regex.Pattern (начинаются со строки 1625) вы увидите код, который сканирует регулярное выражение на наличие дополнительных символов и решает, поддерживать их в сканировании или нет.
Проблема этого подхода заключается в том, что в коде не учитывается тот факт, что даже если регулярное выражение не имеет дополнительных символов, оно все равно может захотеть сопоставить их, как, например, в вашем случае.
Решение состоит в том, чтобы разработать некоторое регулярное выражение, содержащее дополнительные символы, но они не влияют на процесс сопоставления. Я предлагаю вам использовать что-то невинное, как это:
Pattern nonWordRegex = Pattern.compile("(?U)(?!\uDB80\uDC00)[\\W]");
Часть (?!\uDB80\uDC00)
делает трюк. Это негативный взгляд на персонажа в закрытом диапазоне дополнительных символов, что означает, что, скорее всего, вы не найдете его в тексте. И вуаля: движок регулярных выражений считает, что в шаблоне есть дополнительные символы, и включает их поддержку!