Conversione di simboli, lettere di accento in alfabeto inglese


129

Il problema è che, come sai, ci sono migliaia di caratteri nel grafico Unicode e voglio convertire tutti i caratteri simili in lettere che sono in alfabeto inglese.

Ad esempio, ecco alcune conversioni:

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

e ho visto che ci sono più di 20 versioni della lettera A / a. e non so come classificarli. Sembrano aghi nel pagliaio.

L'elenco completo dei caratteri unicode è disponibile all'indirizzo http://www.ssec.wisc.edu/~tomw/java/unicode.html o http://unicode.org/charts/charindex.html . Prova a scorrere verso il basso e vedi le variazioni delle lettere.

Come posso convertire tutti questi con Java? Mi aiuti per favore :(


Vedi questa domanda: stackoverflow.com/questions/249087/… - Dovrebbero esserci anche altre domande su questo argomento, ma al momento non riesco a trovarle.
Schnaader,

1
Il tuo terzo esempio dovrebbe essere Ȳ → Y?
Dour High Arch,

2
Perchè vuoi fare questo? Se sapessimo qual era il tuo obiettivo generale, potremmo essere più utili.
David Thornley,

David, sai che alcuni EMO usano diversi caratteri nelle frasi. Ecco un esempio: ฬ. ¢. tђє ฬ ย η∂єг ¢ ค ק ђ Ŧ ค ๓ เ ℓy <- Risolvi questo :) @schnaader, penso che sia quello che sto cercando ma non in Java.
AhmetB - Google,

Questa conversazione è già stata eseguita in precedenza: vedere @schnaader sopra.
dkretz,

Risposte:


197

Ripubblicazione del mio post da Come rimuovo i segni diacritici (accenti) da una stringa in .NET?

Questo metodo funziona perfettamente con Java (esclusivamente allo scopo di rimuovere segni diacritici o accenti) .

In pratica converte tutti i personaggi accentati nelle loro controparti deAccentate seguite dalla combinazione dei segni diacritici. Ora puoi usare una regex per eliminare i segni diacritici.

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

4
InCombiningDiacriticalMarks non converte tutti i cirillici. Ad esempio, Општина Богомила non è toccato. Sarebbe bello se si potesse convertirlo in Opstina Bogomila o qualcosa del genere
iwein

13
Non si traduce affatto. Rimuove semplicemente i segni diacritici decomposti ("accenti"). Il passaggio precedente (Form.NFD) scompone á in + ', cioè scomporre il carattere accentato in un carattere non accentato più un segno diacritico. Ciò trasformerebbe il cirillico Ѽ in Ѡ ma non oltre.
MSalters,

1
George ha pubblicato che potrebbe essere meglio usare \\ p {IsM} invece di \\ p {InCombiningDiacriticalMarks} su glaforge.appspot.com/article/… Nota che non l'ho provato.
ATorras,

2
\\ p {IsM} non sembra funzionare con accenti spagnoli come á ó ú ñ é í. Al contrario, "\\ p {InCombiningDiacriticalMarks} + sta funzionando bene per questo
Loic

Non funziona per tutti i caratteri speciali - ho inviato un problema sbagliato ad Android per farcelo sapere -> code.google.com/p/android/issues/detail?id=189515 Qualcuno conosce il modo corretto per farlo?
Michał Tajchert,

71

Fa parte di Apache Commons Lang a partire dalla ver. 3.0.

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

ritorna An

Vedi anche http://www.drillio.com/en/software-development/java/removing-accents-diacritics-in-any-language/


Questa soluzione è sorprendente. Funziona anche con il greco! Grazie.
Tom,

5
Non è perfetto per la traduzione dei caratteri polacchi da ł e Ł mancante: input: ŚŻÓŁĄĆĘŹąółęąćńŃ output: SZOŁACEZaołeacnN
Robert

1
Bella utility ma dal momento che il suo codice è esattamente lo stesso di quello mostrato nella risposta accettata, e non vuoi aggiungere una dipendenza da Commons Lang, puoi semplicemente usare lo snippet di cui sopra.
polaretto,

1
con apache comune nel mio caso: Đ non convertire in D
Hoang

@Hoang, Robert forse la possibilità di inviare una richiesta pull :)
Ondra Žižka,

19

Tentare di "convertirli tutti" è l'approccio sbagliato al problema.

Innanzitutto, è necessario comprendere i limiti di ciò che si sta tentando di fare. Come altri hanno sottolineato, i segni diacritici sono lì per una ragione: sono essenzialmente lettere uniche nell'alfabeto di quella lingua con il loro significato / suono, ecc .: rimuovere quei segni è lo stesso che sostituire le lettere casuali in una parola inglese. Questo è ancora prima di prendere in considerazione le lingue cirilliche e altri testi basati su script come l'arabo, che semplicemente non possono essere "convertiti" in inglese.

Se è necessario , per qualsiasi motivo, convertire i personaggi, l'unico modo sensato di affrontarlo per ridurre innanzitutto l'ambito dell'attività a portata di mano. Considera la fonte dell'input: se stai codificando un'applicazione per "il mondo occidentale" (per usare una frase buona come una qualsiasi), è improbabile che tu abbia mai bisogno di analizzare i caratteri arabi. Allo stesso modo, il set di caratteri Unicode contiene centinaia di simboli matematici e pittorici: non c'è modo (facile) per gli utenti di inserirli direttamente, quindi puoi presumere che possano essere ignorati.

Effettuando questi passaggi logici è possibile ridurre il numero di caratteri possibili per analizzare al punto in cui è possibile un'operazione di ricerca / sostituzione basata su dizionario. Diventa quindi una piccola quantità di lavoro leggermente noioso creando i dizionari e un compito banale per eseguire la sostituzione. Se la tua lingua supporta i caratteri Unicode nativi (come fa Java) e ottimizza correttamente le strutture statiche, tale ricerca e sostituzione tendono ad essere sorprendentemente veloci.

Ciò deriva dall'esperienza di aver lavorato su un'applicazione richiesta per consentire agli utenti finali di cercare dati bibliografici che includessero caratteri diacritici. Le matrici di ricerca (come era nel nostro caso) hanno richiesto forse 1 giorno uomo per produrre, per coprire tutti i segni diacritici per tutte le lingue dell'Europa occidentale.


Grazie per aver risposto. In realtà non sto lavorando con le lingue arabe o qualcosa del genere. Sai che alcune persone usano i segni diacritici come personaggi divertenti e devo rimuoverlo il più possibile. Ad esempio, ho detto la conversione "tђє Ŧ ค ๓ เ ℓy -> the Family" nell'esempio, ma sembra difficile convertirlo completamente. Tuttavia, possiamo fare la conversione "òéışöç-> oeisoc" in modo semplice. Ma qual è il modo esatto per farlo. Creazione di array e sostituzione manuale? O questa lingua ha funzioni native su questo problema?
AhmetB - Google,

15

Poiché la codifica che trasforma "la Famiglia" in "tђє Ŧ ค ๓ เ ℓy" è effettivamente casuale e non segue alcun algoritmo che può essere spiegato dalle informazioni dei punti di codice Unicode coinvolti, non esiste un modo generale per risolverlo algoritmicamente.

Dovrai costruire la mappatura dei caratteri Unicode in caratteri latini a cui assomigliano. Probabilmente potresti farlo con un po 'di machine learning intelligente sui glifi reali che rappresentano i punti di codice Unicode. Ma penso che lo sforzo per questo sarebbe maggiore della costruzione manuale di quella mappatura. Soprattutto se hai una buona quantità di esempi da cui puoi costruire la tua mappatura.

Per chiarire: alcune delle sostituzioni possono effettivamente essere risolte tramite i dati Unicode (come dimostrano le altre risposte), ma alcune lettere semplicemente non hanno un'associazione ragionevole con i caratteri latini a cui assomigliano.

Esempi:

  • "ђ" (U + 0452 LETTERA PICCOLA LETTERA DJE) è più correlato a "d" che a "h", ma è usato per rappresentare "h".
  • "Ŧ" (U + 0166 LETTERA MAIUSCOLA T CON CORSA) è in qualche modo correlata a "T" (come suggerisce il nome) ma è usata per rappresentare "F".
  • "ค" (U + 0E04 THAI CHARACTER KHO KHWAI) non è affatto correlato a nessun carattere latino e nel tuo esempio viene usato per rappresentare "a"

7

La richiesta originale ha già ricevuto risposta.

Tuttavia, sto pubblicando la risposta di seguito per coloro che potrebbero essere alla ricerca di un codice di traslitterazione generico per traslitterare qualsiasi set di caratteri in latino / inglese in Java.

Significato ingenuo di traslitterazione: la stringa tradotta nella sua forma finale / charset target suona come la stringa nella sua forma originale. Se vogliamo traslitterare qualsiasi set di caratteri in latino (alfabeti inglesi), allora ICU4 (libreria ICU4J in Java) farà il lavoro.

Ecco lo snippet di codice 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;
    }

7

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

Testato:

  • Uscita da Apache Commons Lang3 : AAAAAÆCEEEEIIIIÐNOOOOOØUUUUYß
  • Uscita da ICU4j : AAAAAÆCEEEEIIIIÐNOOOOOØUUUUYß
  • Uscita da JUnidecode : AAAAAAECEEEEIIIIDNOOOOOOUUUUUss (problema con Ý e un altro problema )
  • Uscita da Unidecode : AAAAAAECEEEEIIIIDNOOOOOOUUUUYss

L'ultima scelta è la migliore.


1
@mehmet Segui il readme su github.com/xuender/unidecode . Dovrebbe essere qualcosa come Unidecode.decode ("ÁÂÃÅÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝß") dopo aver importato la dipendenza.
cactuschibre,

6

Se è necessario convertire "òéışöç-> oeisoc", è possibile utilizzare questo come punto di partenza:

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
    }
}

JDK 1.6 fornisce la classe java.text.Normalizer che può essere utilizzata per questa attività.

Vedi un esempio qui


Sfortunatamente questo non gestirà le legature come Æ.
Dour High Arch,

Questo metodo è particolarmente utile se è necessario rilevare e gestire classi di segni diacritici in modo diverso (ad esempio, sfuggire a caratteri speciali in LaTeX).
vallismortis,

4

Puoi provare a usare unidecode, che è disponibile come gemma rubino e come modulo perl su cpan . In sostanza, funziona come un'enorme tabella di ricerca, in cui ogni punto di codice unicode si riferisce a un carattere o una stringa ASCII.


Potresti essere in grado di ottenere una tabella di ricerca da uno di questi.
Kathy Van Stone,

Questo è un pacchetto fantastico, ma traduce il suono del personaggio, ad esempio converte "北" in "Bei" perché è quello che il personaggio suona in mandarino. Penso che l'interrogante voglia convertire glifi in ciò che assomigliano visivamente in inglese.
Dour High Arch,

Lo fa per i personaggi latini, però. â diventa a, et al. @ahmetalpbalkan Sono d'accordo con Kathy, potresti usarlo come risorsa per costruire la tua tabella di ricerca, la logica dovrebbe essere piuttosto semplice. Sfortunatamente non sembra esserci una versione java.
Daniel Vandersluis,

@ahmetalpbalkan Ecco unidecode per Java.
Jakub Jirutka,

4

Non esiste un modo semplice o generale per fare ciò che vuoi perché è solo la tua opinione soggettiva che queste lettere sembrano loke le lettere latine in cui vuoi convertire. Sono in realtà lettere separate con i loro nomi e suoni distinti che sembrano apparire superficialmente come una lettera latina.

Se vuoi quella conversione, devi creare la tua tabella di traduzione in base a quali lettere latine pensi che le lettere non latine dovrebbero essere convertite.

(Se desideri rimuovere solo segni diacritici, ci sono alcune risposte in questo thread: Come rimuovo i segni diacritici (accenti) da una stringa in .NET? Tuttavia descrivi un problema più generale)


+1. Ecco una versione Java della domanda "rimuovi i segni diacritici": stackoverflow.com/questions/1016955/… ; vedere le risposte di Michael Borgwardt e
Devio

4

Sono in ritardo alla festa, ma dopo aver affrontato questo problema oggi, ho trovato questa risposta molto buona:

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

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


Piccolo avvertimento: rimuove U + 00DF LATINA PICCOLA LETTERA AFFILATO S "ß"
rafalmag

E anche Æ ... Peccato.
cactuschibre,

4

Il problema con "convertire" Unicode arbitrario in ASCII è che il significato di un personaggio dipende dalla cultura. Ad esempio, "ß" in una persona di lingua tedesca dovrebbe essere convertito in "ss" mentre un madrelingua inglese probabilmente lo convertirà in "B".

Aggiungete a ciò il fatto che Unicode ha più punti di codice per gli stessi glifi.

Il risultato è che l'unico modo per farlo è creare una tabella enorme con ogni carattere Unicode e il carattere ASCII in cui si desidera convertirlo. Puoi prendere una scorciatoia normalizzando i caratteri con accenti al modulo di normalizzazione KD, ma non tutti i caratteri si normalizzano in ASCII. Inoltre, Unicode non definisce quali parti di un glifo sono "accenti".

Ecco un piccolo estratto da un'app che fa questo:

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...
}

Sono d'accordo. È necessario creare un dizionario di conversioni specifico per l'applicazione e il pubblico previsto. Ad esempio, per un pubblico di lingua spagnola traduco solo ÁÉÍÓÚÜÑáéíóúü¿¡
Roberto Bonvallet,

Roberto ci sono migliaia di personaggi e non posso fare questo manuale.
AhmetB - Google,

2
Quale linguaggio umano stai usando che ha "migliaia" di caratteri? Giapponese? Cosa ti aspetteresti di convertire in ど う し よ う と し て い ま す か?
Dour High Arch,

6
L'esempio che hai fornito non è l'ideale: U + 00DF TAGLIERINA LATINA PICCOLA LATINA S "ß" non è la stessa lettera Unicode di U + 03B2 LETTERA PICCOLA GRECIA BETA "β".
Joachim Sauer,

2

La seguente classe fa il trucco:

org.apache.lucene.analysis.miscellaneous.ASCIIFoldingFilter
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.