2013-03-07 22 views
9

Ich habe ein Programm, das Strings herausfiltert, indem es jedes Zeichen entfernt, das kein Buchstabe oder eine Ziffer ist. Dieses Programm eine hohe Anzahl von Sprachen unterstützen, die chinesische umfassen, Russisch, Arabisch, usw. Das Programm ist wie folgt:Braucht Character.isLetter normalisierten Text?

StringBuilder strBuilder = new StringBuilder(); 

for (int i = 0; i < src.length(); i++) { 
    int ch = src.codePointAt(i); 
    if (Character.isLetterOrDigit(ch)) { 
     strBuilder.appendCodePoint(ch); 
    } 
} 

I verwenden codePointAt Verfahren Zeichen zu unterstützen, die in UTF 32 Bits über hohe und niedrige exprimiert werden Surrogat. Ich muss wissen, ob jeder String vor der Filterung normalisiert werden muss? Ich beziehe mich auf den Aufruf der Normalizer.normalize Methode vor dem Ausführen der Schleife. Wenn ja, welche Normalizer.Form soll ich verwenden?

Danke.

+1

Können Sie keine Tests für beide Fälle erstellen, d. H. Mit und ohne Normalisierung, und die Ergebnisse vergleichen? – Henrik

Antwort

0

Beachten Sie, dass Ihr Code die Codepoints für Iterieren nicht ganz richtig ist, ich glaube, Sie wollen:

for(int cp, i = 0; i < s.length(); i += Character.charCount(cp)) { 
    cp = s.codePointAt(i); 
    // Process cp... 
} 

sorry, weiß nicht, ob Sie normalisieren oder nicht müssen, though.

+0

OK danke für diesen Fang. Haben Sie einen Hinweis auf die Frage, ob Sie den Normalizer verwenden müssen oder nicht? – user2144762

4

Es hängt alles davon ab, wie Sie wirklich wollen, dass sich Ihr Algorithmus verhält.

Als Beispiel sei (  ʟᴇᴛᴛᴇʀ   ᴀ gefolgt von U + 0308   ᴄᴏᴍʙɪɴɪɴɢ   ᴅɪᴀᴇʀᴇsɪs U + 0061   ʟᴀᴛɪɴ   sᴍᴀʟʟ), die Zeichenfolge "a\u0308" zu berücksichtigen, die zu "ä" oder "\u00e4" kanonisch äquivalent ist (U + 00E4     s         (s). Kanonisch äquivalent zu sein, bedeutet, dass Ihr Algorithmus nicht zwischen diesen beiden unterscheiden sollte. Eine einfache Möglichkeit, kanonisch äquivalente Strings zu erhalten, um sich gleich zu verhalten, besteht darin, die beiden auf das gleiche kanonische Normalisierungsformat zu normieren: entweder NFC oder NFD.

Je nachdem, was diese Zeichenfolgen darstellen, möchten Sie möglicherweise stattdessen die Kompatibilitätsäquivalenz (NFKC oder NFKD) verwenden. Dies wird allgemein beispielsweise für Kennungen empfohlen. Diese beiden konvertieren Kompatibilitätszeichen in ihre empfohlenen Äquivalente (wie U2126   S0 bis U3A9       oder Ligaturzeichen zu den Sequenzen von Zeichen, aus denen sie bestehen).

Unabhängig davon, welche Art von Äquivalenz Sie wollen, bleibt das Prinzip das gleiche: Wenn Sie äquivalente Strings gleichermaßen behandeln wollen, ist die Normalisierung beider Methoden der einfachste Weg.

Sobald Sie das gleiche Verhalten für alle äquivalenten Strings haben, müssen Sie ein anderes Problem betrachten: Wenn Sie alle "Zeichen [s], die [sind] kein Buchstabe oder eine Ziffer sind", was passiert mit Strings mit Buchstaben und Kombinationszeichen, wie "\u092C\u093F" (U + 092C   ᴅᴇᴠᴀɴᴀɢᴀʀɪ   ʟᴇᴛᴛᴇʀ   ʙᴀ gefolgt von U + 093F   ᴅᴇᴠᴀɴᴀɢᴀʀɪ   ᴠᴏᴡᴇʟ   sɪɢɴ   ɪ, sieht aus wie बि)? Dies sind zwei separate Codepunkte und U + 093F ist kein Buchstabe. Diese beiden bilden keine Normalisierungsform. Möchten Sie, dass die Kombinationszeichen gelöscht werden (was Sie mit ब zurücklässt) oder nicht?

Wenn das Löschen erfolgreich ist, können Sie Ihren aktuellen Algorithmus verwenden. Andernfalls möchten Sie wahrscheinlich über Graphem-Cluster iterieren, bei denen es sich grob um Sequenzen von Basiszeichen gefolgt von den Kombinationsmarken handelt.Sowohl Java als auch ICU bieten APIs zum Auffinden von Graphem-Clustern (Java nennt diese "Zeichenumbrüche").