web-dev-qa-db-fra.com

Comparaison de chaînes JavaScript insensible à la casse

Comment puis-je effectuer une comparaison de chaînes sans distinction de casse en JavaScript?

827
flybywire

Le moyen le plus simple de le faire (si vous n'êtes pas inquiet à propos des caractères Unicode spéciaux) est d'appeler toUpperCase:

var areEqual = string1.toUpperCase() === string2.toUpperCase();
951
SLaks

EDIT: Cette réponse a été ajoutée il y a 9 ans. Aujourd'hui, vous devriez utiliser localeCompare avec l'option sensitivity: 'accent':

function ciEquals(a, b) {
    return typeof a === 'string' && typeof b === 'string'
        ? a.localeCompare(b, undefined, { sensitivity: 'accent' }) === 0
        : a === b;
}

console.log("'a' = 'a'?", ciEquals('a', 'a'));
console.log("'AaA' = 'aAa'?", ciEquals('AaA', 'aAa'));
console.log("'a' = 'á'?", ciEquals('a', 'á'));
console.log("'a' = 'b'?", ciEquals('a', 'b'));

Le { sensitivity: 'accent' } indique à localeCompare() de traiter deux variantes de la même lettre de base comme la même sauf leurs accents sont différents (comme dans le troisième exemple) ci-dessus.

Vous pouvez également utiliser { sensitivity: 'base' }, qui traite deux caractères comme équivalents tant que leur caractère de base est identique (donc A sera traité comme équivalent à á).

Notez que le troisième paramètre de localeCompare n'est pas pris en charge dans IE10 ou version antérieure, ni dans certains navigateurs mobiles (voir le tableau de compatibilité de la page liée ci-dessus). Par conséquent, si vous avez besoin de prendre en charge ces navigateurs, vous devrez se retirer:

function ciEqualsInner(a, b) {
    return a.localeCompare(b, undefined, { sensitivity: 'accent' }) === 0;
}

function ciEquals(a, b) {
    if (typeof a !== 'string' || typeof b !== 'string') {
        return a === b;
    }

    //      v--- feature detection
    return ciEqualsInner('A', 'a')
        ? ciEqualsInner(a, b)
        : /*  fallback approach here  */;
}

_ {Réponse originale

La meilleure façon de faire une comparaison en JavaScript sans tenir compte de la casse est d'utiliser la méthode RegExp match() avec l'indicateur i

Recherche insensible à la casse

Lorsque les deux chaînes comparées sont des variables (et non des constantes), c'est un peu plus compliqué, car vous devez générer un RegExp à partir de la chaîne, mais le passage de cette chaîne au constructeur RegExp peut entraîner des correspondances incorrectes ou des correspondances manquantes si la chaîne a une expression régulière spéciale. personnages dedans.

Si l'internationalisation vous tient à cœur, n'utilisez pas toLowerCase() ou toUpperCase(), car cela ne permet pas des comparaisons précises sans distinction de casse dans toutes les langues.

http://www.i18nguy.com/unicode/turkish-i18n.html

125
Samuel Neff

Avec l'aide de l'expression régulière, nous pouvons également réaliser.

(/keyword/i).test(source)

/i est pour ignorer la casse. Si ce n’est pas nécessaire, nous pouvons ignorer et tester la correspondance sensible à la casse comme

(/keyword/).test(source)
29
SP007

N'oubliez pas que le boîtier est une opération spécifique aux paramètres régionaux. Selon le scénario, vous voudrez peut-être en tenir compte. Par exemple, si vous comparez les noms de deux personnes, vous voudrez peut-être prendre en compte les paramètres régionaux mais si vous comparez des valeurs générées par la machine telles que UUID, vous ne le ferez peut-être pas. C'est pourquoi j'utilise la fonction suivante dans ma bibliothèque utils (notez que la vérification de type n'est pas incluse pour des raisons de performances).

function compareStrings (string1, string2, ignoreCase, useLocale) {
    if (ignoreCase) {
        if (useLocale) {
            string1 = string1.toLocaleLowerCase();
            string2 = string2.toLocaleLowerCase();
        }
        else {
            string1 = string1.toLowerCase();
            string2 = string2.toLowerCase();
        }
    }

    return string1 === string2;
}
26
Shital Shah

Comme indiqué dans de récents commentaires, string::localCompare prend en charge les comparaisons insensibles à la casse (entre autres éléments puissants).

Voici un exemple simple

'xyz'.localeCompare('XyZ', undefined, { sensitivity: 'base' }); // returns 0

Et une fonction générique que vous pourriez utiliser

function equalsIgnoringCase(text, other) {
    text.localeCompare(other, undefined, { sensitivity: 'base' }) === 0;
}

Notez qu'au lieu de undefined, vous devriez probablement entrer les paramètres régionaux avec lesquels vous travaillez. Ceci est important comme indiqué dans les documents MDN

en suédois, ä et a sont des lettres de base séparées

Options de sensibilité

 Sensitivity options tabulated from MDN

Support du navigateur

À la date de publication, UC Browser pour Android et Opera Mini ne pas prend en charge locale et options paramètres. Veuillez vérifier https://caniuse.com/#search=localeCompare pour obtenir des informations à jour.

12
jay

J'ai récemment créé une micro-bibliothèque fournissant des aides pour les chaînes qui ne respectent pas la casse: https://github.com/nickuraltsev/ignore-case . (Il utilise toUpperCase en interne.)

var ignoreCase = require('ignore-case');

ignoreCase.equals('FOO', 'Foo'); // => true
ignoreCase.startsWith('foobar', 'FOO'); // => true
ignoreCase.endsWith('foobar', 'BaR'); // => true
ignoreCase.includes('AbCd', 'c'); // => true
ignoreCase.indexOf('AbCd', 'c'); // => 2
10
Nick Uraltsev

si vous êtes préoccupé par le sens de l'inégalité (peut-être souhaitez-vous trier une liste) vous devez effectuer la conversion de casse en assez grande quantité, et comme il existe plus de caractères minuscules dans unicode que de majuscules, la meilleure conversion est probablement la meilleure utiliser.

function my_strcasecmp( a, b ) 
{
    if((a+'').toLowerCase() > (b+'').toLowerCase()) return 1  
    if((a+'').toLowerCase() < (b+'').toLowerCase()) return -1
    return 0
}

Javascript semble utiliser les paramètres régionaux "C" pour les comparaisons de chaînes afin que l'ordre résultant soitbe moche si les chaînes contiennent des lettres autres que ASCII. on ne peut pas faire grand chose à ce sujet sans faire une inspection beaucoup plus détaillée des cordes.

9
Jasen

Supposons que nous voulions trouver la variable chaîne needle dans la variable chaîne haystack. Il y a trois pièges:

  1. Les applications internationalisées doivent éviter string.toUpperCase et string.toLowerCase. Utilisez une expression régulière qui ignore la casse. Par exemple, var needleRegExp = new RegExp(needle, "i"); suivi de needleRegExp.test(haystack).
  2. En général, vous pourriez ne pas connaître la valeur de needle. Veillez à ce que needle ne contienne aucune expression régulière caractères spéciaux . Échappez-vous avec needle.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");.
  3. Dans d'autres cas, si vous souhaitez associer avec précision needle et haystack, en ignorant simplement la casse, veillez à ajouter "^" au début et "$" à la fin de votre constructeur d'expression régulière.

En prenant en considération les points (1) et (2), un exemple serait: 

var haystack = "A. BAIL. Of. Hay.";
var needle = "bail.";
var needleRegExp = new RegExp(needle.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"), "i");
var result = needleRegExp.test(haystack);
if (result) {
    // Your code here
}
5
Chris Chute

Beaucoup de réponses ici, mais j'aime bien ajouter une solution basée sur l'extension de la librairie String:

String.prototype.equalIgnoreCase = function(str)
{
    return (str != null 
            && typeof str === 'string'
            && this.toUpperCase() === str.toUpperCase());
}

De cette façon, vous pouvez simplement l'utiliser comme vous le faites en Java!

Exemple:

var a = "hello";
var b = "HeLLo";
var c = "world";

if (a.equalIgnoreCase(b)) {
    document.write("a == b");
}
if (a.equalIgnoreCase(c)) {
    document.write("a == c");
}
if (!b.equalIgnoreCase(c)) {
    document.write("b != c");
}

La sortie sera:

"a == b"
"b != c"

String.prototype.equalIgnoreCase = function(str) {
  return (str != null &&
    typeof str === 'string' &&
    this.toUpperCase() === str.toUpperCase());
}


var a = "hello";
var b = "HeLLo";
var c = "world";

if (a.equalIgnoreCase(b)) {
  document.write("a == b");
  document.write("<br>");
}
if (a.equalIgnoreCase(c)) {
  document.write("a == c");
}
if (!b.equalIgnoreCase(c)) {
  document.write("b != c");
}

4
Nebulosar

Il y a deux manières de faire une comparaison insensible à la casse:

  1. Convertissez les chaînes en majuscules, puis comparez-les à l'aide de l'opérateur strict (===). Comment un opérateur strict traite les opérandes en lisant les choses à: http://www.thesstech.com/javascript/relational-logical-operators
  2. Pattern matching en utilisant des méthodes de chaîne:

Utilisez la méthode de chaîne "search" pour la recherche ne respectant pas la casse . Pour en savoir plus sur la recherche et les autres méthodes de chaîne, rendez-vous à l'adresse suivante: http://www.thesstech.com/pattern-matching-using-string-methods

<!doctype html>
  <html>
    <head>
      <script>

        // 1st way

        var a = "Apple";
        var b = "Apple";  
        if (a.toUpperCase() === b.toUpperCase()) {
          alert("equal");
        }

        //2nd way

        var a = " Null and void";
        document.write(a.search(/null/i)); 

      </script>
    </head>
</html>
4
Sohail Arif
str = 'Lol', str2 = 'lOl', regex = new RegExp('^' + str + '$', 'i');
if (regex.test(str)) {
    console.log("true");
}
3
Parth Raval

utilisez regex pour la correspondance ou la comparaison de chaînes, 

en javaScript, vous pouvez utiliser match () pour comparer les chaînes, n'oubliez pas de mettre i dans regex  

exemple : 

var matchString = "Test" ;
if(matchString.match(/test/i) ){
  alert('String matched) ;
}else{
 alert('String not matched') ;
}
2
Om Sharma

Pourquoi ne pas lancer d'exceptions et NE PAS utiliser une expression régulière lente?

return str1 != null && str2 != null 
    && typeof str1 === 'string' && typeof str2 === 'string'
    && str1.toUpperCase() === str2.toUpperCase();

L'extrait ci-dessus suppose que vous ne voulez pas faire correspondre si l'une des chaînes est nulle ou indéfinie.

Si vous voulez faire correspondre null/undefined, alors:

return (str1 == null && str2 == null)
    || (str1 != null && str2 != null 
        && typeof str1 === 'string' && typeof str2 === 'string'
        && str1.toUpperCase() === str2.toUpperCase());

Si pour une raison quelconque vous vous souciez de undefined vs null:

return (str1 === undefined && str2 === undefined)
    || (str1 === null && str2 === null)
    || (str1 != null && str2 != null 
        && typeof str1 === 'string' && typeof str2 === 'string'
        && str1.toUpperCase() === str2.toUpperCase());
2
Ben Wilde

Même cette question a déjà répondu. J'ai une approche différente pour utiliser RegExp et correspondre pour ignorer la casse. S'il vous plaît voir mon lien https://jsfiddle.net/marchdave/7v8bd7dq/27/

$("#btnGuess").click(guessWord);

  function guessWord() {

   var letter = $("#guessLetter").val();
   var Word = 'ABC';
   var pattern = RegExp(letter, 'gi'); // pattern: /a/gi

   var result = Word.match(pattern);
   alert('Ignore case sensitive:' + result);

  }
2
David S Lee

J'ai écrit une extension. très trivial

if (typeof String.prototype.isEqual!= 'function') {
    String.prototype.isEqual = function (str){
        return this.toUpperCase()==str.toUpperCase();
     };
}
2
KhanSharp

Si les deux chaînes ont les mêmes paramètres régionaux connus, vous pouvez utiliser un objet Intl.Collator comme ceci:

function equalIgnoreCase(s1: string, s2: string) {
    return new Intl.Collator("en-US", { sensitivity: "base" }).compare(s1, s2) === 0;
}

Évidemment, vous voudrez peut-être mettre en cache la Collator pour une meilleure efficacité.

L'avantage de cette approche est qu'elle devrait être beaucoup plus rapide que RegExps et repose sur un ensemble extrêmement personnalisable (voir la description des paramètres du constructeur locales et options dans l'article ci-dessus) de collateurs prêts à l'emploi.

1
Alexander Abakumov

Puisqu'aucune réponse ne fournissait clairement un extrait de code simple d'utilisation de RegExp, voici ma tentative:

function compareInsensitive(str1, str2){ 
  return typeof str1 === 'string' && 
    typeof str2 === 'string' && 
    new RegExp("^" + str1.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') + "$", "i").test(str2);
}

Il présente plusieurs avantages:

  1. Vérifie le type de paramètre (tout paramètre non-chaîne, comme undefined par exemple, planterait une expression comme str1.toUpperCase()).
  2. Ne souffre pas d'éventuels problèmes d'internationalisation.
  3. Echappe à la chaîne RegExp.
1
Ohad Schneider

Ceci est une version améliorée de cette réponse .

String.equal = function (s1, s2, ignoreCase, useLocale) {
    if (s1 == null || s2 == null)
        return false;

    if (!ignoreCase) {
        if (s1.length !== s2.length)
            return false;

        return s1 === s2;
    }

    if (useLocale) {
        if (useLocale.length)
            return s1.toLocaleLowerCase(useLocale) === s2.toLocaleLowerCase(useLocale)
        else
            return s1.toLocaleLowerCase() === s2.toLocaleLowerCase()
    }
    else {
        if (s1.length !== s2.length)
            return false;

        return s1.toLowerCase() === s2.toLowerCase();
    }
}



Usages & tests:

String.equal = function (s1, s2, ignoreCase, useLocale) {
    if (s1 == null || s2 == null)
        return false;

    if (!ignoreCase) {
        if (s1.length !== s2.length)
            return false;

        return s1 === s2;
    }

    if (useLocale) {
        if (useLocale.length)
            return s1.toLocaleLowerCase(useLocale) === s2.toLocaleLowerCase(useLocale)
        else
            return s1.toLocaleLowerCase() === s2.toLocaleLowerCase()
    }
    else {
        if (s1.length !== s2.length)
            return false;

        return s1.toLowerCase() === s2.toLowerCase();
    }
}

// If you don't mind extending the prototype.
String.prototype.equal = function(string2, ignoreCase, useLocale) {
  return String.equal(this.valueOf(), string2, ignoreCase, useLocale);
}

// ------------------ TESTS ----------------------
console.log("Tests...");

console.log('Case sensitive 1');
var result = "Abc123".equal("Abc123");
console.assert(result === true);

console.log('Case sensitive 2');
result = "aBC123".equal("Abc123");
console.assert(result === false);

console.log('Ignore case');
result = "AbC123".equal("aBc123", true);
console.assert(result === true);

console.log('Ignore case + Current locale');
result = "AbC123".equal("aBc123", true);
console.assert(result === true);

console.log('Turkish test 1 (ignore case, en-US)');
result = "IiiI".equal("ıiİI", true, "en-US");
console.assert(result === false);

console.log('Turkish test 2 (ignore case, tr-TR)');
result = "IiiI".equal("ıiİI", true, "tr-TR");
console.assert(result === true);

console.log('Turkish test 3 (case sensitive, tr-TR)');
result = "IiiI".equal("ıiİI", false, "tr-TR");
console.assert(result === false);

console.log('null-test-1');
result = "AAA".equal(null);
console.assert(result === false);

console.log('null-test-2');
result = String.equal(null, "BBB");
console.assert(result === false);

console.log('null-test-3');
result = String.equal(null, null);
console.assert(result === false);

0
Sergey

Convertissez les deux en abaissement (une seule fois pour des raisons de performances) et comparez-les avec l'opérateur ternaire sur une seule ligne:

function strcasecmp(s1,s2){
    s1=(s1+'').toLowerCase();
    s2=(s2+'').toLowerCase();
    return s1>s2?1:(s1<s2?-1:0);
}
0
Luca C.