2013-12-10 14 views
8

Die fragliche Zeichenfolge hat ein zusätzliches Unicode-Zeichen "\ ud84c \ udfb4". Laut javadoc sollte der Regex-Abgleich auf Codepunkt-Ebene und nicht auf Zeichenebene erfolgen. Der folgende Teilcode behandelt jedoch den niedrigen Ersatz (\ udbb4) als Nicht-Wort-Zeichen und teilt es auf.Java 7, Regexes und zusätzliche Unicode-Zeichen

Fehle ich etwas? Welche Alternativen gibt es, um Nicht-Wort-Zeichen aufzuteilen? (Java-Version "1.7.0_07")

Vielen Dank im Voraus.

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(); 
} 

Output:
original 功能 絶 顯示 廣告
ursprünglichen hex 529f 80fd 20 7d76 d84c dfb4 986f 793a 5ee3 544a
0 529f 80fd
1 7d76 d84c
2 986f 793a 5ee3 544a

Antwort

9

Das sieht einfach wie ein Fehler in der Regex-Engine aus. Wenn Sie den Ausdruck \w verwenden, stimmt alles korrekt überein, bleibt ein einzelner Codepunkt, der aus zwei Zeichen besteht. Dies kann leicht mit dem folgenden Code überprüft werden:

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

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

Ich habe gerade eine durchgehende Untersuchung, und so kann ich Ihnen sagen, wo das Problem ist. Wenn Sie die Methode compile() in java.util.regex.Pattern betrachten (in der Zeile 1625 beginnen), sehen Sie den Code, der die Regex nach zusätzlichen Zeichen scannt und entscheidet, ob sie beim Scannen unterstützt werden oder nicht. Das Problem bei diesem Ansatz ist, dass der Code die Tatsache nicht berücksichtigt, dass die Regex auch dann, wenn sie keine zusätzlichen Zeichen hat, sie dennoch abgleichen möchte, wie es in Ihrem Fall beispielsweise der Fall ist .

Die Lösung ist eine Regex zu entwickeln, die die zusätzlichen Zeichen enthält, aber sie haben keinen Einfluss auf den Anpassungsprozess. Ich schlage vor, Sie etwas Unschuldiges wie folgt verwenden:

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

Der Teil (?!\uDB80\uDC00) funktioniert der Trick. Dies ist ein negativer Lookahead für ein Zeichen im privaten Bereich von Zusatzzeichen, was bedeutet, dass Sie es höchstwahrscheinlich nicht im Text finden werden. Und voila: Die Regex-Engine denkt, dass es zusätzliche Zeichen im Muster gibt, und schaltet ihre Unterstützung ein!

+0

Leider behält Matcher die Wortgrenzen nicht bei. Wenn Sie "[^ \\ w]" voraussagen, erhalten Sie dasselbe Ergebnis wie "[\\ W]" Soll ich es irgendwo auf Java-Boards posten? – user3088039

+1

@ user3088039 Ich habe gerade das Problem gelöst! Überprüfen Sie die Antwort noch einmal, ich habe es aktualisiert. – Malcolm

+0

Sie würden denken, dass "(? U)" die Unterstützung zusätzlicher Charaktere aktivieren würde. Danke, dass du unter die Decke geschaut hast. Es funktioniert wunderbar. – user3088039