Conversion de symboles, de lettres d'accentuation en alphabet anglais

129

Le problème est que, comme vous le savez, il y a des milliers de caractères dans le graphique Unicode et je veux convertir tous les caractères similaires en lettres qui sont en alphabet anglais.

Par exemple, voici quelques conversions:

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

et j'ai vu qu'il existe plus de 20 versions de la lettre A / a. et je ne sais pas comment les classer. Ils ressemblent à des aiguilles dans la botte de foin.

La liste complète des caractères Unicode se trouve à http://www.ssec.wisc.edu/~tomw/java/unicode.html ou http://unicode.org/charts/charindex.html . Essayez simplement de faire défiler vers le bas et de voir les variations de lettres.

Comment puis-je convertir tout cela avec Java? Aidez-moi, s'il vous plaît :(

AhmetB - Google
la source
Voir cette question: stackoverflow.com/questions/249087/… - il devrait également y avoir d'autres questions sur ce sujet, mais je ne les trouve pas pour le moment.
schnaader
1
Votre troisième exemple devrait-il être Ȳ → Y?
Dour High Arch
2
Pourquoi veux-tu faire cela? Si nous savions quel était votre objectif global, nous serions peut-être plus utiles.
David Thornley
David, vous savez que certains EMO utilisent différents caractères dans les phrases. Voici un exemple: ฬ. ¢. tђє ฬ ย η∂єг ¢ ค ק ђ Ŧ ค ๓ เ ℓy <- Résolvez ceci :) @schnaader, je pense que c'est ce que je recherche mais pas en Java.
AhmetB - Google le
Cette conversation a déjà été faite - voir @schnaader ci-dessus.
dkretz

Réponses:

197

Republier mon message depuis Comment supprimer les signes diacritiques (accents) d'une chaîne dans .NET?

Cette méthode fonctionne très bien en java (uniquement dans le but de supprimer les signes diacritiques aka accents) .

Il convertit fondamentalement tous les caractères accentués en leurs homologues désaccentués, suivis de leur combinaison de signes diacritiques. Vous pouvez maintenant utiliser une expression régulière pour supprimer les signes diacritiques.

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
la source
4
InCombiningDiacriticalMarks ne convertit pas toutes les cyrilliques. Par exemple, Општина Богомила n'est pas touché. Ce serait bien si on pouvait le convertir en Opstina Bogomila ou quelque chose comme ça
iwein
13
Il ne translittère pas du tout. Il supprime simplement les signes diacritiques décomposés («accents»). L'étape précédente (Form.NFD) décompose á dans un + ', c'est-à-dire décomposer le caractère accentué en un caractère non accentué plus un signe diacritique. Cela convertirait Ѽ cyrillique en Ѡ mais pas plus.
MSalters
1
George a posté qu'il pourrait être préférable d'utiliser \\ p {IsM} au lieu de \\ p {InCombiningDiacriticalMarks} sur glaforge.appspot.com/article/... Notez que je ne l'ai pas testé.
ATorras
2
\\ p {IsM} ne semble pas fonctionner pour les accents espagnols comme á ó ú ñ é í. Au contraire, "\\ p {InCombiningDiacriticalMarks} + fonctionne bien pour cela
Loic
Cela ne fonctionne pas pour tous les caractères spéciaux - j'ai soumis un problème erroné pour Android pour savoir cela -> code.google.com/p/android/issues/detail?id=189515 Quelqu'un sait-il comment faire cela?
Michał Tajchert
71

Il fait partie d' Apache Commons Lang à partir de la ver. 3.0.

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

Retour An

Voir également http://www.drillio.com/en/software-development/java/removing-accents-diacritics-in-any-language/

Ondra Žižka
la source
Cette solution est incroyable. Cela fonctionne aussi avec le grec! Je vous remercie.
Tom
5
Ce n'est pas parfait pour la traduction des caractères polonais à partir de ł et il manque Ł: entrée: ŚŻÓŁĄĆĘŹąółęąćńŃ sortie: SZOŁACEZaołeacnN
Robert
1
Bel utilitaire mais comme son code est exactement le même que celui indiqué dans la réponse acceptée et que vous ne voulez pas ajouter de dépendance à Commons Lang, vous pouvez simplement utiliser l'extrait de code susmentionné.
polaretto
1
avec apache commun dans mon cas: Đ ne pas convertir en D
Hoang
@Hoang, Robert peut-être une chance d'envoyer une demande de tirage :)
Ondra Žižka
19

Tenter de «tous les convertir» est une mauvaise approche du problème.

Tout d'abord, vous devez comprendre les limites de ce que vous essayez de faire. Comme d'autres l'ont souligné, les signes diacritiques sont là pour une raison: ce sont essentiellement des lettres uniques dans l'alphabet de cette langue avec leur propre signification / son, etc.: supprimer ces marques équivaut à remplacer des lettres aléatoires dans un mot anglais. C'est avant même de commencer à considérer les langues cyrilliques et d'autres textes basés sur des scripts tels que l'arabe, qui ne peuvent tout simplement pas être «convertis» en anglais.

Si vous devez , pour une raison quelconque, convertir des caractères, alors la seule façon raisonnable de l'aborder est de réduire d'abord la portée de la tâche à accomplir. Considérez la source de l'entrée - si vous codez une application pour "le monde occidental" (pour utiliser une phrase aussi bonne que n'importe quelle autre), il est peu probable que vous ayez jamais besoin d'analyser les caractères arabes. De même, le jeu de caractères Unicode contient des centaines de symboles mathématiques et illustrés: il n'y a pas de moyen (facile) pour les utilisateurs de les saisir directement, vous pouvez donc supposer qu'ils peuvent être ignorés.

En suivant ces étapes logiques, vous pouvez réduire le nombre de caractères possibles à analyser au point où une opération de recherche / remplacement basée sur le dictionnaire est possible. Cela devient alors une petite quantité de travail légèrement ennuyeux pour créer les dictionnaires, et une tâche triviale pour effectuer le remplacement. Si votre langage prend en charge les caractères Unicode natifs (comme le fait Java) et optimise correctement les structures statiques, cette recherche et ces remplacements ont tendance à être incroyablement rapides.

Cela vient de l'expérience d'avoir travaillé sur une application qui était nécessaire pour permettre aux utilisateurs finaux de rechercher des données bibliographiques contenant des caractères diacritiques. Les tableaux de recherche (comme c'était le cas dans notre cas) ont pris peut-être 1 jour d'homme à produire, pour couvrir toutes les marques diacritiques de toutes les langues d'Europe occidentale.

Ian
la source
Merci d'avoir répondu. En fait, je ne travaille pas avec les langues arabes ou quelque chose comme ça. Vous savez que certaines personnes utilisent les signes diacritiques comme des personnages amusants et je dois les supprimer autant que je peux. Par exemple, j'ai dit la conversion "tђє Ŧ ค ๓ เ ℓy -> la famille" dans l'exemple, mais il semble difficile de la convertir complètement. Cependant, nous pouvons faire la conversion "òéışöç-> oeisoc" d'une manière simple. Mais quelle est la manière exacte de le faire. Créer des tableaux et les remplacer manuellement? Ou cette langue a-t-elle des fonctions natives sur ce problème?
AhmetB - Google
15

Puisque le codage qui transforme «la famille» en «tђє Ŧ ค ๓ เ ℓy» est effectivement aléatoire et ne suit aucun algorithme qui peut être expliqué par les informations des points de code Unicode impliqués, il n'y a pas de moyen général de résoudre ce problème de manière algorithmique.

Vous devrez construire le mappage des caractères Unicode en caractères latins auxquels ils ressemblent. Vous pourriez probablement le faire avec un apprentissage automatique intelligent sur les glyphes réels représentant les points de code Unicode. Mais je pense que l'effort pour cela serait plus grand que la construction manuelle de cette cartographie. Surtout si vous disposez d'une bonne quantité d'exemples à partir desquels vous pouvez construire votre cartographie.

Pour clarifier: quelques-unes des substitutions peuvent en fait être résolues via les données Unicode (comme le montrent les autres réponses), mais certaines lettres n'ont tout simplement aucune association raisonnable avec les caractères latins auxquels elles ressemblent.

Exemples:

  • "ђ" (U + 0452 CYRILLIC MINUSCULE DJE) est plus lié à "d" qu'à "h", mais est utilisé pour représenter "h".
  • "Ŧ" (U + 0166 LETTRE MAJUSCULE LATINE T AVEC RACCORD) est quelque peu lié à "T" (comme son nom l'indique) mais est utilisé pour représenter "F".
  • "ค" (U + 0E04 THAI CARACTER KHO KHWAI) n'est pas du tout lié à un caractère latin et dans votre exemple est utilisé pour représenter "a"
Joachim Sauer
la source
7

La demande d'origine a déjà reçu une réponse.

Cependant, je publie la réponse ci-dessous pour ceux qui pourraient rechercher un code de translittération générique pour translittérer n'importe quel jeu de caractères en latin / anglais en Java.

Signification naïve de la traduction: la chaîne traduite dans sa forme finale / jeu de caractères cible sonne comme la chaîne dans sa forme originale. Si nous voulons translittérer n'importe quel jeu de caractères en latin (alphabets anglais), alors ICU4 (bibliothèque ICU4J en java) fera le travail.

Voici l'extrait de code en 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
la source
7

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

Testé:

  • Sortie d' Apache Commons Lang3 : AAAAAÆCEEEEIIIIÐNOOOOOØUUUUYß
  • Sortie d' ICU4j : AAAAAÆCEEEEIIIIÐNOOOOOØUUUUYß
  • Sortie de JUnidecode : AAAAAAECEEEEIIIIDNOOOOOOUUUUUss (problème avec Ý et un autre problème )
  • Sortie de Unidecode : AAAAAAECEEEEIIIIDNOOOOOOUUUUYss

Le dernier choix est le meilleur.

cactuschibre
la source
1
@mehmet Suivez simplement le readme sur github.com/xuender/unidecode . Cela devrait être quelque chose comme Unidecode.decode ("ÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝß") après l'importation de la dépendance.
cactuschibre
6

Si le besoin est de convertir "òéışöç-> oeisoc", vous pouvez utiliser ceci comme point de départ:

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

Le JDK 1.6 fournit la classe java.text.Normalizer qui peut être utilisée pour cette tâche.

Voir un exemple ici

RealHowTo
la source
Malheureusement, cela ne gère pas les ligatures comme Æ.
Dour High Arch
Cette méthode est particulièrement utile si vous avez besoin de détecter et de gérer différemment les classes de signes diacritiques (c'est-à-dire, échapper des caractères spéciaux dans LaTeX).
vallismortis
4

Vous pouvez essayer d'utiliser unidecode, qui est disponible en tant que gemme ruby et en tant que module perl sur cpan . Essentiellement, cela fonctionne comme une énorme table de recherche, où chaque point de code Unicode se rapporte à un caractère ou une chaîne ascii.

Daniel Vandersluis
la source
Vous pourrez peut-être obtenir une table de recherche à partir de l'un d'entre eux.
Kathy Van Stone
C'est un package étonnant, mais il translittère le son du personnage, par exemple il convertit "北" en "Bei" parce que c'est ce à quoi ressemble le personnage en mandarin. Je pense que le questionneur veut convertir les glyphes en ce qu'ils ressemblent visuellement en anglais.
Dour High Arch
Cependant, il le fait pour les caractères latins. â devient a, et al. @ahmetalpbalkan Je suis d'accord avec Kathy, vous pouvez l'utiliser comme une ressource pour créer votre propre table de recherche, la logique devrait être assez simple. Malheureusement, il ne semble pas y avoir de version java.
Daniel Vandersluis
@ahmetalpbalkan Voici unidecode pour Java.
Jakub Jirutka
4

Il n'y a pas de moyen facile ou général de faire ce que vous voulez, car c'est juste votre opinion subjective que ces lettres ressemblent aux lettres latines vers lesquelles vous voulez convertir. Ce sont en fait des lettres séparées avec leurs propres noms et sons distincts qui ressemblent simplement à une lettre latine.

Si vous voulez cette conversion, vous devez créer votre propre table de traduction en fonction des lettres latines vers lesquelles vous pensez que les lettres non latines doivent être converties.

(Si vous souhaitez uniquement supprimer les signes diacritiques, il y a quelques réponses dans ce fil: Comment supprimer les signes diacritiques (accents) d'une chaîne dans .NET? Cependant, vous décrivez un problème plus général)

JacquesB
la source
+1. Voici une version Java de la question «supprimer les signes diacritiques»: stackoverflow.com/questions/1016955/… ; voir les réponses de Michael Borgwardt et devio
Jonik
4

Je suis en retard à la fête, mais après avoir affronté ce problème aujourd'hui, j'ai trouvé cette réponse très bonne:

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

Référence: https://stackoverflow.com/a/16283863

Francisco Junior
la source
Petit avertissement - il supprime U + 00DF LATIN SMALL LETTER SHARP S "ß"
rafalmag
Et aussi Æ ... Dommage.
cactuschibre
4

Le problème de la «conversion» de l'Unicode arbitraire en ASCII est que la signification d'un caractère dépend de la culture. Par exemple, «ß» pour une personne de langue allemande devrait être converti en «ss» alors qu'un anglophone le convertirait probablement en «B».

Ajoutez à cela le fait qu'Unicode a plusieurs points de code pour les mêmes glyphes.

Le résultat est que la seule façon de le faire est de créer une table massive avec chaque caractère Unicode et le caractère ASCII vers lequel vous souhaitez le convertir. Vous pouvez prendre un raccourci en normalisant les caractères avec des accents au formulaire de normalisation KD, mais tous les caractères ne se normalisent pas en ASCII. De plus, Unicode ne définit pas quelles parties d'un glyphe sont des «accents».

Voici un petit extrait d'une application qui fait cela:

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
la source
Je suis d'accord. Vous devez créer un dictionnaire de conversions spécifiquement pour votre application et le public attendu. Par exemple, pour un public hispanophone, je traduirais uniquement ÁÉÍÓÚÜÑáéíóúü¿¡
Roberto Bonvallet le
Roberto il y a des milliers de caractères et je ne peux pas faire ce manuel.
AhmetB - Google
2
Quel langage humain utilisez-vous qui contient des «milliers» de caractères? Japonais? À quoi vous attendriez-vous que ど う し よ う と し て い ま す か soit converti?
Dour High Arch
6
L'exemple que vous avez donné n'est pas idéal: U + 00DF LETTRE MINUSCULE LATINE SHARP S "ß" n'est pas la même lettre Unicode que U + 03B2 LETTRE MINUSCULE GRECQUE BÊTA "β".
Joachim Sauer
2

La classe suivante fait l'affaire:

org.apache.lucene.analysis.miscellaneous.ASCIIFoldingFilter
TomWolk
la source