85 votes

Supprimer les signes diacritiques (ń ǹ ň ñ ṅ ņ ṇ ṋ ṉ ̈ ɲ ƞ ᶇ ɳ ȵ) des caractères Unicode.

Je cherche un algorithme capable de faire correspondre des caractères avec des signes diacritiques ( tilde , circonflexe , caret , tréma , caron ) et leur caractère "simple".

Par exemple :

      ñ                     --> n
á --> a
ä --> a
 --> a
 --> o

Etc.

  1. Je veux le faire en Java, bien que je soupçonne qu'il devrait s'agir de quelque chose d'Unicode et qu'il devrait être possible de le faire raisonnablement facilement dans n'importe quel langage.

  2. Objectif : permettre de rechercher facilement des mots comportant des signes diacritiques. Par exemple, si j'ai une base de données de joueurs de tennis et que Björn_Borg est saisi, je conserverai également Bjorn_Borg afin de pouvoir le retrouver si quelqu'un saisit Bjorn et non Björn.

77voto

Andreas Petersson Points 8096

C'est ce que j'ai fait récemment en Java :

public static final Pattern DIACRITICS_AND_FRIENDS
    = Pattern.compile("[\\p{InCombiningDiacriticalMarks}\\p{IsLm}\\p{IsSk}]+");

private static String stripDiacritics(String str) {
    str = Normalizer.normalize(str, Normalizer.Form.NFD);
    str = DIACRITICS_AND_FRIENDS.matcher(str).replaceAll("");
    return str;
}

Cela se passera comme vous l'avez spécifié :

stripDiacritics("Björn")  = Bjorn

mais elle échouera, par exemple, à Białystok, parce que les ł n'est pas un diacritique.

Si vous souhaitez disposer d'un véritable simplificateur de chaînes, vous aurez besoin d'un deuxième cycle de nettoyage, pour d'autres caractères spéciaux qui ne sont pas des diacritiques. Dans cette carte, j'ai inclus les caractères spéciaux les plus courants qui apparaissent dans les noms de nos clients. Cette liste n'est pas exhaustive, mais elle vous donnera une idée de la façon de procéder pour l'étendre. L'immutableMap est une simple classe de google-collections.

public class StringSimplifier {
    public static final char DEFAULT_REPLACE_CHAR = '-';
    public static final String DEFAULT_REPLACE = String.valueOf(DEFAULT_REPLACE_CHAR);
    private static final ImmutableMap<String, String> NONDIACRITICS = ImmutableMap.<String, String>builder()

        //Remove crap strings with no sematics
        .put(".", "")
        .put("\"", "")
        .put("'", "")

        //Keep relevant characters as seperation
        .put(" ", DEFAULT_REPLACE)
        .put("]", DEFAULT_REPLACE)
        .put("[", DEFAULT_REPLACE)
        .put(")", DEFAULT_REPLACE)
        .put("(", DEFAULT_REPLACE)
        .put("=", DEFAULT_REPLACE)
        .put("!", DEFAULT_REPLACE)
        .put("/", DEFAULT_REPLACE)
        .put("\\", DEFAULT_REPLACE)
        .put("&", DEFAULT_REPLACE)
        .put(",", DEFAULT_REPLACE)
        .put("?", DEFAULT_REPLACE)
        .put("°", DEFAULT_REPLACE) //Remove ?? is diacritic?
        .put("|", DEFAULT_REPLACE)
        .put("<", DEFAULT_REPLACE)
        .put(">", DEFAULT_REPLACE)
        .put(";", DEFAULT_REPLACE)
        .put(":", DEFAULT_REPLACE)
        .put("_", DEFAULT_REPLACE)
        .put("#", DEFAULT_REPLACE)
        .put("~", DEFAULT_REPLACE)
        .put("+", DEFAULT_REPLACE)
        .put("*", DEFAULT_REPLACE)

        //Replace non-diacritics as their equivalent characters
        .put("\u0141", "l") // BiaLystock
        .put("\u0142", "l") // Bialystock
        .put("ß", "ss")
        .put("æ", "ae")
        .put("ø", "o")
        .put("©", "c")
        .put("\u00D0", "d") // All Ð ð from http://de.wikipedia.org/wiki/%C3%90
        .put("\u00F0", "d")
        .put("\u0110", "d")
        .put("\u0111", "d")
        .put("\u0189", "d")
        .put("\u0256", "d")
        .put("\u00DE", "th") // thorn Þ
        .put("\u00FE", "th") // thorn þ
        .build();

    public static String simplifiedString(String orig) {
        String str = orig;
        if (str == null) {
            return null;
        }
        str = stripDiacritics(str);
        str = stripNonDiacritics(str);
        if (str.length() == 0) {
            // Ugly special case to work around non-existing empty strings
            // in Oracle. Store original crapstring as simplified.
            // It would return an empty string if Oracle could store it.
            return orig;
        }
        return str.toLowerCase();
    }

    private static String stripNonDiacritics(String orig) {
        StringBuilder ret = new StringBuilder
        String lastchar = null;
        for (int i = 0; i < orig.length(); i++) {
            String source = orig.substring(i, i + 1);
            String replace = NONDIACRITICS.get(source);
            String toReplace = replace == null ? String.valueOf(source) : replace;
            if (DEFAULT_REPLACE.equals(lastchar) && DEFAULT_REPLACE.equals(toReplace)) {
                toReplace = "";
            } else {
                lastchar = toReplace;
            }
            ret.append(toReplace);
        }
        if (ret.length() > 0 && DEFAULT_REPLACE_CHAR == ret.charAt(ret.length() - 1)) {
            ret.deleteCharAt(ret.length() - 1);
        }
        return ret.toString();
    }

    /*
    Special regular expression character ranges relevant for simplification -> see http://docstore.mik.ua/orelly/perl/prog3/ch05_04.htm
    InCombiningDiacriticalMarks: special marks that are part of "normal" ä, ö, î etc..
        IsSk: Symbol, Modifier see http://www.fileformat.info/info/unicode/category/Sk/list.htm
        IsLm: Letter, Modifier see http://www.fileformat.info/info/unicode/category/Lm/list.htm
     */
    public static final Pattern DIACRITICS_AND_FRIENDS
        = Pattern.compile("[\\p{InCombiningDiacriticalMarks}\\p{IsLm}\\p{IsSk}]+");

    private static String stripDiacritics(String str) {
        str = Normalizer.normalize(str, Normalizer.Form.NFD);
        str = DIACRITICS_AND_FRIENDS.matcher(str).replaceAll("");
        return str;
    }
}

23voto

erickson Points 127945

Le paquetage java.text a été conçu pour répondre à ce cas d'utilisation (faire correspondre des chaînes de caractères sans se soucier des signes diacritiques, de la casse, etc.)

Configurer un Collator à trier sur PRIMARY les différences de caractères. A partir de là, créez un CollationKey pour chaque chaîne. Si tout votre code est en Java, vous pouvez utiliser la fonction CollationKey directement. Si vous devez stocker les clés dans une base de données ou dans un autre type d'index, vous pouvez [le convertir en tableau d'octets](http://java.sun.com/javase/6/docs/api/java/text/CollationKey.html#toByteArray()) .

Ces classes utilisent la méthode Norme Unicode les données de pliage de cas pour déterminer quels caractères sont équivalents, et prendre en charge divers types de caractères. décomposition stratégies.

Collator c = Collator.getInstance();
c.setStrength(Collator.PRIMARY);
Map<CollationKey, String> dictionary = new TreeMap<CollationKey, String>();
dictionary.put(c.getCollationKey("Björn"), "Björn");
...
CollationKey query = c.getCollationKey("bjorn");
System.out.println(dictionary.get(query)); // --> "Björn"

Il est à noter que les collateurs sont spécifiques à chaque pays. En effet, l'"ordre alphabétique" diffère d'une locale à l'autre (et même au fil du temps, comme c'est le cas pour l'espagnol). Le collateur Collator vous évite d'avoir à suivre toutes ces règles et à les tenir à jour.

16voto

Kenston Choi Points 1138

Il fait partie de Apache Commons Lang à partir de ver. 3.1.

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

retours An

11voto

nils Points 474

Vous pouvez utiliser le Classe de normalisation de java.text :

System.out.println(new String(Normalizer.normalize("ń ǹ ň ñ ṅ ņ ṇ ṋ", Normalizer.Form.NFKD).getBytes("ascii"), "ascii"));

Mais il y a encore du travail à faire, car Java fait des choses étranges avec les caractères Unicode non convertibles (il ne les ignore pas et ne lance pas d'exception). Mais je pense que vous pouvez utiliser cela comme point de départ.

10voto

ire_and_curses Points 32802

Il existe un projet de rapport sur le pliage des caractères sur le site web d'Unicode qui contient de nombreux documents pertinents. Voir en particulier la section 4.1. "Algorithme de pliage".

Voici une discussion et mise en œuvre de l'élimination des signes diacritiques en utilisant Perl.

Ces questions relatives à l'OS sont liées entre elles :

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X