Konvertieren von Symbolen, Akzentbuchstaben in englisches Alphabet

129

Das Problem ist, dass, wie Sie wissen, das Unicode-Diagramm Tausende von Zeichen enthält und ich alle ähnlichen Zeichen in die Buchstaben des englischen Alphabets konvertieren möchte.

Zum Beispiel hier ein paar Konvertierungen:

ҥ->H
Ѷ->V
Ȳ->Y
Ǭ->O
Ƈ->C
tђє Ŧค๓เℓy --> the Family
...

und ich habe gesehen, dass es mehr als 20 Versionen von Buchstabe A / a gibt. und ich weiß nicht, wie ich sie klassifizieren soll. Sie sehen aus wie Nadeln im Heuhaufen.

Die vollständige Liste der Unicode-Zeichen finden Sie unter http://www.ssec.wisc.edu/~tomw/java/unicode.html oder http://unicode.org/charts/charindex.html . Scrollen Sie einfach nach unten und sehen Sie die Variationen der Buchstaben.

Wie kann ich all dies mit Java konvertieren? Bitte hilf mir :(

AhmetB - Google
quelle
Siehe diese Frage: stackoverflow.com/questions/249087/… - Es sollte auch einige andere Fragen zu diesem Thema geben, aber ich kann sie momentan nicht finden.
Schnaader
1
Sollte Ihr drittes Beispiel Ȳ → Y sein?
Dour High Arch
2
Warum willst du das tun? Wenn wir wüssten, was Ihr übergeordnetes Ziel war, könnten wir möglicherweise hilfreicher sein.
David Thornley
David, Sie wissen, dass einige EMOs unterschiedliche Zeichen in Sätzen verwenden. Hier ein Beispiel: ฬ. ¢. tђє ฬ η η∂єг ¢ ค ק ђ Ŧ ค ๓ เy <- Löse das :) @schnaader, ich denke, das ist es, wonach ich suche, aber nicht in Java.
AhmetB - Google
Dieses Gespräch wurde bereits zuvor geführt - siehe @schnaader oben.
dkretz

Antworten:

197

Reposting my post from Wie entferne ich diakritische Zeichen (Akzente) aus einer Zeichenfolge in .NET?

Diese Methode funktioniert gut in Java (nur zum Entfernen diakritischer Zeichen, auch Akzente genannt) .

Grundsätzlich werden alle Zeichen mit Akzent in ihre Gegenstücke mit Akzent umgewandelt, gefolgt von ihren kombinierten Diakritika. Jetzt können Sie eine Regex verwenden, um die Diakritika zu entfernen.

import java.text.Normalizer;
import java.util.regex.Pattern;

public String deAccent(String str) {
    String nfdNormalizedString = Normalizer.normalize(str, Normalizer.Form.NFD); 
    Pattern pattern = Pattern.compile("\\p{InCombiningDiacriticalMarks}+");
    return pattern.matcher(nfdNormalizedString).replaceAll("");
}
Hashable
quelle
4
InCombiningDiacriticalMarks konvertiert nicht alle Kyrilliken. Zum Beispiel ist Општина Богомила unberührt. Es wäre schön, wenn man es in Opstina Bogomila oder so
umwandeln
13
Es transliteriert überhaupt nicht. Es werden lediglich zerlegte diakritische Zeichen ("Akzente") entfernt. Der vorherige Schritt (Form.NFD) zerlegt á in ein + ', dh das Zerlegen des akzentuierten Zeichens in ein nicht akzentuiertes Zeichen plus eine diakritische Markierung. Dies würde kyrillisches Ѽ in Ѡ umwandeln, aber nicht weiter.
MSalters
1
George gab unter glaforge.appspot.com/article/… bekannt, dass es besser sein könnte, das \\ p {IsM} anstelle von \\ p {InCombiningDiacriticalMarks} zu verwenden .
ATorras
2
\\ p {IsM} scheint nicht für spanische Akzente wie á ó ú ñ é í zu funktionieren. Im Gegenteil, "\\ p {InCombiningDiacriticalMarks} + funktioniert gut dafür
Loic
Es funktioniert nicht für alle Sonderzeichen - ich habe ein falsches Problem für Android eingereicht, um dies zu erfahren -> code.google.com/p/android/issues/detail?id=189515 Weiß jemand, wie man das richtig macht?
Michał Tajchert
71

Es ist ein Teil von Apache Commons Lang ab Version. 3.0.

org.apache.commons.lang3.StringUtils.stripAccents("Añ");

kehrt zurück An

Siehe auch http://www.drillio.com/de/software-development/java/removing-accents-diacritics-in-any-language/

Ondra Žižka
quelle
Diese Lösung ist erstaunlich. Es funktioniert auch mit Griechisch! Danke dir.
Tom
5
Es ist nicht perfekt für polnische Zeichen Übersetzung von ł und Ł fehlt: Eingabe: ŚŻÓŁĄĆĘŹąółęąćńŃ Ausgabe: SZOŁACEZaołeacnN
Robert
1
Nettes Dienstprogramm, aber da der Code genau dem entspricht, der in der akzeptierten Antwort angezeigt wird, und Sie keine Abhängigkeit von Commons Lang hinzufügen möchten, können Sie einfach das oben genannte Snippet verwenden.
Polaretto
1
mit Apache in meinem Fall häufig: Đ nicht zu D konvertieren
Hoang
@Hoang, Robert vielleicht eine Chance, eine Pull-Anfrage zu senden :)
Ondra Žižka
19

Der Versuch, "alle zu konvertieren", ist die falsche Herangehensweise an das Problem.

Zunächst müssen Sie die Einschränkungen dessen verstehen, was Sie versuchen zu tun. Wie andere bereits betont haben, gibt es Diakritika aus einem Grund: Es handelt sich im Wesentlichen um eindeutige Buchstaben im Alphabet dieser Sprache mit eigener Bedeutung / Ton usw. Das Entfernen dieser Zeichen ist genau das gleiche wie das Ersetzen zufälliger Buchstaben in einem englischen Wort. Dies ist, bevor Sie sich überhaupt mit den kyrillischen Sprachen und anderen skriptbasierten Texten wie Arabisch befassen, die einfach nicht in Englisch "konvertiert" werden können.

Wenn Sie aus irgendeinem Grund Zeichen konvertieren müssen, ist dies der einzig sinnvolle Weg, um zunächst den Umfang der vorliegenden Aufgabe zu verringern. Betrachten Sie die Quelle der Eingabe - wenn Sie eine Anwendung für "die westliche Welt" codieren (um eine so gute Phrase wie jede andere zu verwenden), ist es unwahrscheinlich, dass Sie jemals arabische Zeichen analysieren müssen. In ähnlicher Weise enthält der Unicode-Zeichensatz Hunderte von mathematischen und bildlichen Symbolen: Es gibt keine (einfache) Möglichkeit für Benutzer, diese direkt einzugeben, sodass Sie davon ausgehen können, dass sie ignoriert werden können.

Mit diesen logischen Schritten können Sie die Anzahl der möglichen zu analysierenden Zeichen so weit reduzieren, dass eine wörterbuchbasierte Such- / Ersetzungsoperation möglich ist. Es wird dann zu einer kleinen Menge etwas langweiliger Arbeit beim Erstellen der Wörterbücher und zu einer trivialen Aufgabe, den Austausch durchzuführen. Wenn Ihre Sprache native Unicode-Zeichen unterstützt (wie Java) und statische Strukturen korrekt optimiert, sind solche Suchen und Ersetzen in der Regel unglaublich schnell.

Dies beruht auf der Erfahrung, an einer Anwendung gearbeitet zu haben, die erforderlich war, damit Endbenutzer bibliografische Daten mit diakritischen Zeichen durchsuchen konnten. Die Erstellung der Lookup-Arrays (wie in unserem Fall) dauerte vielleicht 1 Manntag, um alle diakritischen Zeichen für alle westeuropäischen Sprachen abzudecken.

Ian
quelle
Vielen Dank für Ihre Antwort. Eigentlich arbeite ich nicht mit arabischen Sprachen oder so. Sie wissen, dass einige Leute die Diakritika als lustige Zeichen verwenden, und ich muss das so weit wie möglich entfernen. Zum Beispiel habe ich im Beispiel "tђє Ŧ ค ๓ เ ℓy -> die Familie" -Konvertierung gesagt, aber es scheint schwierig, sie vollständig zu konvertieren. Wir können die Konvertierung "òéışöç-> oeisoc" jedoch auf einfache Weise vornehmen. Aber wie geht das genau? Arrays erstellen und manuell ersetzen? Oder hat diese Sprache native Funktionen zu diesem Thema?
AhmetB - Google
15

Da die Codierung, die "die Familie" in "tђє Ŧ Ŧ ๓ เ ℓy" verwandelt, effektiv zufällig ist und keinem Algorithmus folgt, der durch die Informationen der beteiligten Unicode-Codepunkte erklärt werden kann, gibt es keine allgemeine Möglichkeit, dies algorithmisch zu lösen.

Sie müssen die Zuordnung von Unicode-Zeichen zu lateinischen Zeichen erstellen, denen sie ähneln. Sie könnten dies wahrscheinlich mit intelligentem maschinellem Lernen an den tatsächlichen Glyphen tun, die die Unicode-Codepunkte darstellen. Aber ich denke, der Aufwand dafür wäre größer als das manuelle Erstellen dieses Mappings. Vor allem, wenn Sie eine gute Anzahl von Beispielen haben, aus denen Sie Ihr Mapping erstellen können.

Zur Verdeutlichung: Einige der Substitutionen können tatsächlich über die Unicode-Daten gelöst werden (wie die anderen Antworten zeigen), aber einige Buchstaben haben einfach keine vernünftige Assoziation mit den lateinischen Zeichen, denen sie ähneln.

Beispiele:

  • "ђ" (U + 0452 CYRILLIC SMALL LETTER DJE) ist eher mit "d" als mit "h" verwandt, wird jedoch zur Darstellung von "h" verwendet.
  • "Ŧ" (U + 0166 LATEINISCHER GROSSBUCHSTABE T MIT SCHLAG) ist etwas mit "T" verwandt (wie der Name schon sagt), wird jedoch zur Darstellung von "F" verwendet.
  • "ค" (U + 0E04 THAI CHARACTER KHO KHWAI) ist überhaupt nicht mit einem lateinischen Zeichen verwandt und wird in Ihrem Beispiel verwendet, um "a" darzustellen.
Joachim Sauer
quelle
7

Die ursprüngliche Anfrage wurde bereits beantwortet.

Ich poste jedoch die folgende Antwort für diejenigen, die möglicherweise nach generischem Transliterationscode suchen, um Zeichensätze in Java auf Latein / Englisch zu transliterieren.

Naive Bedeutung der Übersetzung: Übersetzte Zeichenfolge in ihrer endgültigen Form / Zielzeichensatz klingt wie die Zeichenfolge in ihrer ursprünglichen Form. Wenn wir einen Zeichensatz ins Lateinische (englische Alphabete) übersetzen möchten, erledigt ICU4 (ICU4J-Bibliothek in Java) die Aufgabe.

Hier ist das Code-Snippet in Java:

    import com.ibm.icu.text.Transliterator; //ICU4J library import

    public static String TRANSLITERATE_ID = "NFD; Any-Latin; NFC";
    public static String NORMALIZE_ID = "NFD; [:Nonspacing Mark:] Remove; NFC";

    /**
    * Returns the transliterated string to convert any charset to latin.
    */
    public static String transliterate(String input) {
        Transliterator transliterator = Transliterator.getInstance(TRANSLITERATE_ID + "; " + NORMALIZE_ID);
        String result = transliterator.transliterate(input);
        return result;
    }
Dayanand Gowda
quelle
7

Saite getestet: ÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝß

Geprüft :

  • Ausgabe von Apache Commons Lang3 : AAAAAÆCEEEEIIIIÐNOOOOOØUUUUYß
  • Ausgabe von ICU4j : AAAAAÆCEEEEIIIIÐNOOOOOØUUUUYß
  • Ausgabe von JUnidecode : AAAAAAECEEEEIIIIDNOOOOOOUUUUUss (Problem mit Ý und ein anderes Problem )
  • Ausgabe von Unidecode : AAAAAAECEEEEIIIIDNOOOOOOUUUUYss

Die letzte Wahl ist die beste.

cactuschibre
quelle
1
@mehmet Folgen Sie einfach der Readme-Datei unter github.com/xuender/unidecode . Es sollte nach dem Importieren der Abhängigkeit so etwas wie Unidecode.decode ("ÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝß") sein.
Cactuschibre
6

Wenn "òéışöç-> oeisoc" konvertiert werden muss, können Sie dies als Ausgangspunkt verwenden:

public class AsciiUtils {
    private static final String PLAIN_ASCII =
      "AaEeIiOoUu"    // grave
    + "AaEeIiOoUuYy"  // acute
    + "AaEeIiOoUuYy"  // circumflex
    + "AaOoNn"        // tilde
    + "AaEeIiOoUuYy"  // umlaut
    + "Aa"            // ring
    + "Cc"            // cedilla
    + "OoUu"          // double acute
    ;

    private static final String UNICODE =
     "\u00C0\u00E0\u00C8\u00E8\u00CC\u00EC\u00D2\u00F2\u00D9\u00F9"             
    + "\u00C1\u00E1\u00C9\u00E9\u00CD\u00ED\u00D3\u00F3\u00DA\u00FA\u00DD\u00FD" 
    + "\u00C2\u00E2\u00CA\u00EA\u00CE\u00EE\u00D4\u00F4\u00DB\u00FB\u0176\u0177" 
    + "\u00C3\u00E3\u00D5\u00F5\u00D1\u00F1"
    + "\u00C4\u00E4\u00CB\u00EB\u00CF\u00EF\u00D6\u00F6\u00DC\u00FC\u0178\u00FF" 
    + "\u00C5\u00E5"                                                             
    + "\u00C7\u00E7" 
    + "\u0150\u0151\u0170\u0171" 
    ;

    // private constructor, can't be instanciated!
    private AsciiUtils() { }

    // remove accentued from a string and replace with ascii equivalent
    public static String convertNonAscii(String s) {
       if (s == null) return null;
       StringBuilder sb = new StringBuilder();
       int n = s.length();
       for (int i = 0; i < n; i++) {
          char c = s.charAt(i);
          int pos = UNICODE.indexOf(c);
          if (pos > -1){
              sb.append(PLAIN_ASCII.charAt(pos));
          }
          else {
              sb.append(c);
          }
       }
       return sb.toString();
    }

    public static void main(String args[]) {
       String s = 
         "The result : È,É,Ê,Ë,Û,Ù,Ï,Î,À,Â,Ô,è,é,ê,ë,û,ù,ï,î,à,â,ô,ç";
       System.out.println(AsciiUtils.convertNonAscii(s));
       // output : 
       // The result : E,E,E,E,U,U,I,I,A,A,O,e,e,e,e,u,u,i,i,a,a,o,c
    }
}

Das JDK 1.6 stellt die Klasse java.text.Normalizer bereit, die für diese Aufgabe verwendet werden kann.

Sehen Sie ein Beispiel hier

RealHowTo
quelle
Leider können damit keine Ligaturen wie Æ behandelt werden.
Dour High Arch
Diese Methode ist besonders nützlich, wenn Sie diakritische Klassen unterschiedlich erkennen und behandeln müssen (dh ohne Sonderzeichen in LaTeX).
Vallismortis
4

Sie können versuchen unidecode, das zu verwenden , das als Ruby Gem und als Perl-Modul auf cpan erhältlich ist . Im Wesentlichen funktioniert es als riesige Nachschlagetabelle, in der sich jeder Unicode-Codepunkt auf ein ASCII-Zeichen oder eine ASCII-Zeichenfolge bezieht.

Daniel Vandersluis
quelle
Möglicherweise können Sie eine Nachschlagetabelle von einer dieser Tabellen abrufen.
Kathy Van Stone
Dies ist ein erstaunliches Paket, aber es transkribiert den Klang des Charakters, zum Beispiel konvertiert es "北" in "Bei", weil der Charakter so in Mandarin klingt. Ich denke, der Fragesteller möchte Glyphen in das umwandeln, was sie visuell auf Englisch ähneln.
Dour High Arch
Dies geschieht jedoch für lateinische Zeichen. â wird a, et al. @ahmetalpbalkan Ich stimme Kathy zu, Sie könnten es als Ressource verwenden, um Ihre eigene Nachschlagetabelle zu erstellen. Die Logik sollte ziemlich einfach sein. Leider scheint es keine Java-Version zu geben.
Daniel Vandersluis
@ahmetalpbalkan Hier ist Unidecode für Java.
Jakub Jirutka
4

Es gibt keine einfache oder allgemeine Möglichkeit, das zu tun, was Sie wollen, da es nur Ihre subjektive Meinung ist, dass diese Buchstaben wie die lateinischen Buchstaben aussehen, in die Sie konvertieren möchten. Es sind eigentlich getrennte Buchstaben mit ihren eigenen Namen und Lauten, die nur oberflächlich wie ein lateinischer Buchstabe aussehen.

Wenn Sie diese Konvertierung wünschen, müssen Sie eine eigene Übersetzungstabelle erstellen, die darauf basiert, in welche lateinischen Buchstaben die nicht-lateinischen Buchstaben Ihrer Meinung nach konvertiert werden sollen.

(Wenn Sie nur diakritische Zeichen entfernen möchten, gibt es in diesem Thread einige Antworten: Wie entferne ich diakritische Zeichen (Akzente) aus einer Zeichenfolge in .NET? Sie beschreiben jedoch ein allgemeineres Problem.)

JacquesB
quelle
+1. Hier ist eine Java-Version der Frage "Diakritika entfernen": stackoverflow.com/questions/1016955/… ; siehe die Antworten von Michael Borgwardt und devio
Jonik
4

Ich bin zu spät zur Party, aber nachdem ich mich heute diesem Problem gestellt habe, fand ich diese Antwort sehr gut:

String asciiName = Normalizer.normalize(unicodeName, Normalizer.Form.NFD)
    .replaceAll("[^\\p{ASCII}]", "");

Referenz: https://stackoverflow.com/a/16283863

Francisco Junior
quelle
Kleine Warnung - es entfernt U + 00DF LATIN SMALL LETTER SHARP S "ß"
rafalmag
Und auch Æ ... Schade.
Cactuschibre
4

Das Problem beim "Konvertieren" von beliebigem Unicode in ASCII besteht darin, dass die Bedeutung eines Zeichens kulturabhängig ist. Zum Beispiel sollte "ß" für eine deutschsprachige Person in "ss" konvertiert werden, während ein Englisch sprechender es wahrscheinlich in "B" konvertieren würde.

Hinzu kommt, dass Unicode mehrere Codepunkte für dieselben Glyphen hat.

Das Ergebnis ist, dass der einzige Weg, dies zu tun, darin besteht, eine massive Tabelle mit jedem Unicode-Zeichen und dem ASCII-Zeichen zu erstellen, in das Sie es konvertieren möchten. Sie können eine Verknüpfung verwenden, indem Sie Zeichen mit Akzenten zur Normalisierung von KD normalisieren, aber nicht alle Zeichen werden zu ASCII normalisiert. Außerdem definiert Unicode nicht, welche Teile eines Glyphen "Akzente" sind.

Hier ist ein kleiner Auszug aus einer App, die dies tut:

switch (c)
{
    case 'A':
    case '\u00C0':  //  À LATIN CAPITAL LETTER A WITH GRAVE
    case '\u00C1':  //  Á LATIN CAPITAL LETTER A WITH ACUTE
    case '\u00C2':  //  Â LATIN CAPITAL LETTER A WITH CIRCUMFLEX
    // and so on for about 20 lines...
        return "A";
        break;

    case '\u00C6'://  Æ LATIN CAPITAL LIGATURE AE
        return "AE";
        break;

    // And so on for pages...
}
Dour High Arch
quelle
Genau. Sie sollten ein Wörterbuch mit Conversions speziell für Ihre Anwendung und die erwartete Zielgruppe erstellen. Zum Beispiel würde ich für ein spanischsprachiges Publikum nur ÁÉÍÓÚÜÑáéíóúü¿¡
Roberto Bonvallet
Roberto, es gibt Tausende von Charakteren und ich kann dieses Handbuch nicht machen.
AhmetB - Google
2
Welche menschliche Sprache verwenden Sie mit "Tausenden" Zeichen? Japanisch? Was würden Sie erwarten, um in converted う し よ う と し て い ま す か konvertiert zu werden?
Dour High Arch
6
Das Beispiel, das Sie gegeben haben, ist nicht ideal: U + 00DF LATIN SMALL LETTER SHARP S "ß" ist nicht der gleiche Unicode-Buchstabe wie U + 03B2 GREEK SMALL LETTER BETA "β".
Joachim Sauer
2

Die folgende Klasse macht den Trick:

org.apache.lucene.analysis.miscellaneous.ASCIIFoldingFilter
TomWolk
quelle