2013-12-10 4 views
8

В данной строке есть символ unicode «\ ud84c \ udfb4». Согласно javadoc, соответствие регулярному выражению должно выполняться на уровне кодовой точки, а не на уровне символов. Тем не менее, разделенный код ниже рассматривает низкий суррогат (\ udfb4) как символ без слова и разбивается на него.Java 7, регулярные выражения и символы дополнительного уникода

Я что-то упустил? Каковы другие альтернативы для разделения на символы, отличные от слов? (Версия 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 544а
0 529f 80fd
1 7d76 d84c
2 986f 793a 5ee3 544а

ответ

9

Это выглядит просто как ошибка в двигателе регулярных выражений. Если вы используете выражение \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) делает трюк. Это негативный взгляд на персонажа в частном диапазоне дополнительных символов, что означает, что, скорее всего, вы не найдете его в тексте. И voila: движок регулярных выражений считает, что в шаблоне есть дополнительные символы, и он поддерживает их поддержку!

+0

К сожалению, Matcher не сохраняет границы слов. Используя «[^ \\ w]» предсказательно, дает тот же результат, что и «[\\ W]« Должен ли я размещать его на досках Java где-нибудь? – user3088039

+1

@ user3088039 Я только что решил проблему! Проверьте ответ еще раз, я обновил его. – Malcolm

+0

Вы думаете, что «(? U)» включит дополнительную поддержку персонажа. Спасибо, что посмотрели под обложки. Он работает красиво. – user3088039

Смежные вопросы