web-dev-qa-db-fra.com

Utilisation de JavaScript pour effectuer des correspondances de texte avec / sans caractères accentués

J'utilise une recherche basée sur AJAX pour les noms qu'un utilisateur recherche dans une zone de texte.

Je fais l'hypothèse que tous les noms de la base de données seront translittérés en alphabets européens (c'est-à-dire pas de cyrillique, japonais, chinois). Cependant, les noms contiendront toujours des caractères accentués, tels que ç, ê et même č et ć.

Une simple recherche comme "Micic" ne correspondra pas à "Mičić" - et l'utilisateur s'attend à ce que ce soit le cas.

La recherche AJAX utilise des expressions régulières pour déterminer une correspondance. J'ai modifié la comparaison des expressions régulières en utilisant cette fonction pour essayer de faire correspondre des caractères plus accentués. Cependant, c'est un peu maladroit car il ne le fait pas prendre en compte tous les personnages.

function makeComp (input)
{
    input = input.toLowerCase ();
    var output = '';
    for (var i = 0; i < input.length; i ++)
    {
        if (input.charAt (i) == 'a')
            output = output + '[aàáâãäåæ]'
        else if (input.charAt (i) == 'c')
            output = output + '[cç]';
        else if (input.charAt (i) == 'e')
            output = output + '[eèéêëæ]';
        else if (input.charAt (i) == 'i')
            output = output + '[iìíîï]';
        else if (input.charAt (i) == 'n')
            output = output + '[nñ]';
        else if (input.charAt (i) == 'o')
            output = output + '[oòóôõöø]';
        else if (input.charAt (i) == 's')
            output = output + '[sß]';
        else if (input.charAt (i) == 'u')
            output = output + '[uùúûü]';
        else if (input.charAt (i) == 'y')
            output = output + '[yÿ]'
        else
            output = output + input.charAt (i);
    }
    return output;
}

Hormis une fonction de substitution comme celle-ci, y a-t-il une meilleure façon? Peut-être pour "désactiver" la chaîne comparée?

26
Philip

Il existe un moyen de "" désactiver "la chaîne comparée" sans utiliser une fonction de substitution qui répertorie tous les accents que vous souhaitez supprimer…

Voici la solution la plus simple Je peux penser à supprimer les accents (et autres signes diacritiques) d'une chaîne.

Voyez-le en action:

var string = "Ça été Mičić. ÀÉÏÓÛ";
console.log(string);

var string_norm = string.normalize('NFD').replace(/[\u0300-\u036f]/g, "");
console.log(string_norm);
20
Takit Isy

cela devrait aider: son pliage d'accent appelé:

http://alistapart.com/article/accent-folding-for-auto-complete

16
herostwist

Entré sur ce vieux fil et pensé que j'essaierais de faire une fonction rapide. Je me fie à l'ordre des variables de réglage des OR séparés par des tuyaux lorsqu'elles correspondent dans la fonction replace () appelle. Mon objectif était d'utiliser autant que possible la fonction standard de remplacement () de javascript d'implémentation de regex, afin que le traitement intensif puisse avoir lieu dans un espace optimisé par navigateur de bas niveau, au lieu de comparaisons coûteuses char par char javascript .

Ce n'est pas du tout scientifique, mais mon ancien Huawei IDEOS Android est lent lorsque je branche les autres fonctions de ce fil à ma saisie semi-automatique, tandis que cette fonction se poursuit:

function accentFold(inStr) {
  return inStr.replace(
    /([àáâãäå])|([ç])|([èéêë])|([ìíîï])|([ñ])|([òóôõöø])|([ß])|([ùúûü])|([ÿ])|([æ])/g, 
    function (str, a, c, e, i, n, o, s, u, y, ae) {
      if (a) return 'a';
      if (c) return 'c';
      if (e) return 'e';
      if (i) return 'i';
      if (n) return 'n';
      if (o) return 'o';
      if (s) return 's';
      if (u) return 'u';
      if (y) return 'y';
      if (ae) return 'ae';
    }
  );
}

Si vous êtes un développeur jQuery, voici un exemple pratique d'utilisation de cette fonction; vous pouvez utiliser: icontains la même manière que vous utiliseriez: contient dans un sélecteur:

jQuery.expr[':'].icontains = function (obj, index, meta, stack) {
  return accentFold(
    (obj.textContent || obj.innerText || jQuery(obj).text() || '').toLowerCase()
  )
    .indexOf(accentFold(meta[3].toLowerCase())
  ) >= 0;
};
12

Il n'y a pas de moyen plus simple de "désactiver" que je puisse penser, mais votre substitution pourrait être rationalisée un peu plus:

var makeComp = (function(){

    var accents = {
            a: 'àáâãäåæ',
            c: 'ç',
            e: 'èéêëæ',
            i: 'ìíîï',
            n: 'ñ',
            o: 'òóôõöø',
            s: 'ß',
            u: 'ùúûü',
            y: 'ÿ'
        },
        chars = /[aceinosuy]/g;

    return function makeComp(input) {
        return input.replace(chars, function(c){
            return '[' + c + accents[c] + ']';
        });
    };

}());
7
James

J'ai cherché et voté herostwist réponse mais j'ai continué à chercher et vraiment, voici une solution moderne, au cœur de JavaScript ( string.localeCompare fonction)

var a = 'réservé'; // with accents, lowercase
var b = 'RESERVE'; // no accents, uppercase

console.log(a.localeCompare(b));
// expected output: 1
console.log(a.localeCompare(b, 'en', {sensitivity: 'base'}));
// expected output: 0

REMARQUE, cependant, il manque toujours un support complet pour certains navigateurs mobiles !!!

Jusque-là, continuez à surveiller le support complet sur TOUTES les plateformes et env.

Est-ce tout ?

Non, nous pouvons aller plus loin maintenant et utiliser la fonction string.toLocaleLowerCase .

var dotted = 'İstanbul';

console.log('EN-US: ' + dotted.toLocaleLowerCase('en-US'));
// expected output: "istanbul"

console.log('TR: ' + dotted.toLocaleLowerCase('tr'));
// expected output: "istanbul"

Je vous remercie !

3
Salathiel Genèse

J'en ai fait une version prototype:

String.prototype.strip = function() {
  var translate_re = /[öäüÖÄÜß ]/g;
  var translate = {
    "ä":"a", "ö":"o", "ü":"u",
    "Ä":"A", "Ö":"O", "Ü":"U",
    " ":"_", "ß":"ss"   // probably more to come
  };
    return (this.replace(translate_re, function(match){
        return translate[match];})
    );
};

Utilisez comme:

var teststring = 'ä ö ü Ä Ö Ü ß';
teststring.strip();

Cela changera la chaîne en a_o_u_A_O_U_ss

0
Jan Hagge

Je pense que c'est la meilleure solution

var nIC = new Intl.Collator(undefined , {sensitivity: 'base'})
var cmp = nIC.compare.bind(nIC)

Il retournera 0 si les deux chaînes sont identiques, en ignorant les accents.

Vous pouvez également essayer localecompare

'être'.localeCompare('etre',undefined,{sensitivity: 'base'})
0
user1221780

Je cherchais quelque chose de similaire, mais au lieu de créer une expression régulière, je voulais juste remplacer les caractères accentués par leurs équivalents ASCII. Inspiré par la réponse de 999 et un article dans A List Apart ( http://www.alistapart.com/articles/accent-folding-for-auto-complete/ ) Je suis venu avec la fonction suivante. Elle peut être modifiée pour des implémentations spécifiques bien sûr:

var accent_fold = (function () {
    var accent_map = {
        'à': 'a', 'á': 'a', 'â': 'a', 'ã': 'a', 'ä': 'a', 'å': 'a', // a
        'ç': 'c',                                                   // c
        'è': 'e', 'é': 'e', 'ê': 'e', 'ë': 'e',                     // e
        'ì': 'i', 'í': 'i', 'î': 'i', 'ï': 'i',                     // i
        'ñ': 'n',                                                   // n
        'ò': 'o', 'ó': 'o', 'ô': 'o', 'õ': 'o', 'ö': 'o', 'ø': 'o', // o
        'ß': 's',                                                   // s
        'ù': 'u', 'ú': 'u', 'û': 'u', 'ü': 'u',                     // u
        'ÿ': 'y'                                                    // y
    };

    return function accent_fold(s) {
        if (!s) { return ''; }
        var ret = '';
        for (var i = 0; i < s.length; i++) {
            ret += accent_map[s.charAt(i)] || s.charAt(i);
        }
        return ret;
    };
} ());

usage:

var someText = "lôõk mä, nø hånds!";
someText = accent_fold(someText);
// someText now contains: "look ma, no hands!"
0
Mark van Dijk