Comment faire une comparaison de chaînes insensible à la casse?


1057

Comment effectuer une comparaison de chaînes insensible à la casse en JavaScript?


25
voir la .localeCompare()méthode javascript nouvellement ajoutée . Uniquement pris en charge par les navigateurs modernes au moment de l'écriture (IE11 +). voir developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Adrien Be


5
@AdrienBe "A".localeCompare( "a" );revient 1dans la console Chrome 48.
manuell

3
@manuell, ce qui signifie "a"vient avant le "A"tri. Comme "a"avant "b". Si ce comportement n'est pas souhaité, on peut vouloir .toLowerCase()chaque lettre / chaîne. c'est à dire. "A".toLowerCase().localeCompare( "a".toLowerCase() )voir developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
Adrien Be

2
Parce que la comparaison est souvent un terme utilisé pour trier / ordonner les chaînes, je suppose. J'ai commenté ici il y a longtemps maintenant. ===vérifiera l'égalité mais ne sera pas assez bon pour trier / ordonner les chaînes (cf. la question à laquelle j'ai lié à l'origine).
Adrien Be

Réponses:


1163

La façon la plus simple de le faire (si vous ne vous inquiétez pas des caractères Unicode spéciaux) est d'appeler toUpperCase:

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

44
La conversion en majuscules ou minuscules fournit des comparaisons insensibles à la casse dans toutes les langues. i18nguy.com/unicode/turkish-i18n.html
Samuel Neff

57
@sam: Je sais. C'est pourquoi j'ai écrit if you're not worried about special Unicode characters.
SLaks

141
Y at - il une raison de préférer toUpperCaseplus toLowerCase?
jpmc26


19
Est-ce vraiment le meilleur de JS?
Kugel

210

EDIT : Cette réponse a été ajoutée à l'origine il y a 9 ans. Aujourd'hui, vous devez utiliser localeComparel' sensitivity: 'accent'option:

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' }dit localeCompare()de traiter deux variantes de la même lettre de base comme identiques, sauf si elles ont des accents différents (comme dans le troisième exemple) ci-dessus.

Alternativement, vous pouvez utiliser { sensitivity: 'base' }, qui traite deux caractères comme équivalents tant que leur caractère de base est le même (il Aserait donc traité comme équivalent à á).

Remarque que le troisième paramètre de localeComparen'est pas pris en charge dans IE10 ou inférieur ou dans certains navigateurs mobiles (voir le tableau de compatibilité sur la page liée ci-dessus), donc si vous devez prendre en charge ces navigateurs, vous aurez besoin d'une sorte de solution de rechange:

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 insensible à la casse en JavaScript est d'utiliser RegExp match() méthode avec l' iindicateur.

Recherche insensible à la casse

Lorsque les deux chaînes comparées sont des variables (pas 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 la chaîne au constructeur RegExp peut entraîner des correspondances incorrectes ou des correspondances échouées si la chaîne a une expression rationnelle spéciale personnages en elle.

Si vous vous souciez de l'internationalisation, n'utilisez pas toLowerCase()ou toUpperCase()car il ne fournit pas de comparaisons précises insensibles à la casse dans toutes les langues.

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


5
@Quandary, oui, c'est ce que j'ai dit qu'il fallait gérer - "vous devez générer un RegExp à partir de la chaîne mais passer la chaîne au constructeur RegExp peut entraîner des correspondances incorrectes ou des échecs si la chaîne contient des caractères regex spéciaux"
Samuel Neff

21
Son utilisation est la solution la plus coûteuse pour la comparaison de chaînes insensible à la casse. Un RegExp est destiné à une correspondance de modèle complexe, en tant que tel, il doit créer un arbre de décision pour chaque modèle, puis l'exécute contre des chaînes d'entrée. Bien que cela fonctionnerait, c'est comparable à prendre un avion à réaction pour faire du shopping dans le bloc suivant. tl; dr: s'il vous plaît ne faites pas cela.
Agoston Horvath du

2
je pourrais utiliser localeCompare (), mais son retour -1 pour 'a'.localeCompare('A')et comme l'op que je recherche pour comparer la chaîne insensible à la casse.
StingyJack

3
@StingyJack pour faire une comparaison insensible à la casse en utilisant localeCompare, vous devez faire 'a'.localeCompare (' A ', non défini, {sensibilité:' base '})
Judah Gabriel Himango

1
Remarque: La localeCompareversion nécessite que le moteur JavaScript prenne en charge l' API d'internationalisation ECMAScript® , ce qui n'est pas obligatoire. Donc, avant de vous y fier, vous voudrez peut-être vérifier qu'il fonctionne dans l'environnement que vous utilisez. Par exemple: const compareInsensitive = "x".localeCompare("X", undefined, {sensitivity: "base"}) === 0 ? (a, b) => a.localeCompare(b, undefined, {sensitivity: "base"}) : (a, b) => a.toLowerCase().localeCompare(b.toLowerCase());ou quelque chose comme ça.
TJ Crowder

47

Comme indiqué dans des commentaires récents, string::localeCompareprend en charge les comparaisons insensibles à la casse (entre autres choses puissantes).

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) {
    return text.localeCompare(other, undefined, { sensitivity: 'base' }) === 0;
}

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

en suédois, ä et a sont des lettres de base distinctes

Options de sensibilité

Options de sensibilité tabulées à partir de MDN

Prise en charge du navigateur

Au moment de la publication, UC Browser pour Android et Opera Mini ne prend pas en charge les paramètres régionaux et d' options . Veuillez consulter https://caniuse.com/#search=localeCompare pour des informations à jour.


35

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

(/keyword/i).test(source)

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

(/keyword/).test(source)

17
L'utilisation d'une expression régulière comme celle-ci correspondra aux sous-chaînes! Dans votre exemple, la chaîne keyWORDentraînera une correspondance positive. Mais la chaîne this is a keyword yoou keywordsentraînera également une correspondance positive. Soyez conscient de cela :-)
Elmer

6
Cela ne répond pas au contrôle d' égalité (insensible à la casse) comme demandé dans la question! Mais, c'est un chèque Contient ! Ne l'utilisez pas
S.Serpooshan

4
Bien sûr, pour faire correspondre la chaîne entière, l'expression rationnelle peut être changée en /^keyword$/.test(source), mais 1) si ce keywordn'est pas une constante, vous devez le faire new RegExp('^' + x + '$').test(source)et 2) recourir à une expression rationnelle pour tester quelque chose d'aussi simple que l'égalité de chaîne insensible à la casse. pas du tout très efficace.
JHH

28

N'oubliez pas que la casse 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 tenir compte des 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 d'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;
}

Y a-t-il une raison pour laquelle vous utilisez "!!" effectuer une conversion booléenne explicite, au lieu de permettre à la clause if d'évaluer la véracité des valeurs?
Celos

Ce n'est pas obligatoire. Je suppose que je l'ai eu de mon autre version de code plus compliqué. J'ai mis à jour la réponse.
Shital Shah

@thekodester votre fonction a un bug. Cela compareStrings("", "")donnera falsemalgré le fait que les cordes sont égales.
Sergey

@Sergey Faire cela revient truepour moi. C'est peut-être un bug avec votre navigateur?
Jenna Sloan

14

J'ai récemment créé une micro bibliothèque qui fournit des aides de chaîne insensibles à la casse: https://github.com/nickuraltsev/ignore-case . (Il utilise en toUpperCaseinterne.)

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

12

si vous êtes préoccupé par la direction de l'inégalité (peut-être que vous voulez trier une liste), vous devez à peu près faire la conversion de casse, et comme il y a plus de caractères en minuscules en unicode que en majuscules vers LowerCase est probablement la meilleure conversion à 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, donc l'ordre résultant sera moche si les chaînes contiennent des lettres autres que ASCII. il n'y a pas grand-chose à faire à ce sujet sans effectuer une inspection beaucoup plus détaillée des cordes.


7

Supposons que nous voulons trouver la variable chaîne needledans la variable chaîne haystack. Il y a trois pièges:

  1. Les applications internationalisées devraient éviter string.toUpperCaseet string.toLowerCase. Utilisez une expression régulière qui ignore la casse à la place. Par exemple, var needleRegExp = new RegExp(needle, "i");suivi de needleRegExp.test(haystack).
  2. En général, vous ne connaissez peut-être pas la valeur de needle. Attention, needleil ne contient aucun caractère spécial d' expression régulière . Échapper à ces derniers en utilisant needle.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");.
  3. Dans d'autres cas, si vous souhaitez faire correspondre précisément needleet haystack, en ignorant simplement la casse, assurez-vous d'ajouter "^"au début et "$"à la fin de votre constructeur d'expressions régulières.

Compte tenu des 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
}

Tu paries! Tout ce que vous devez faire est de remplacer la new RegExp(...)partie la ligne 3 par ce qui suit: new RegExp("^" + needle.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&") + "$", "i");. Cela garantit qu'il n'y a pas d'autres caractères avant ou après votre chaîne de recherche needle.
Chris Chute

4

Il existe deux façons de comparer 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 lire des trucs à: http://www.thesstech.com/javascript/relational-logical-operators
  2. Correspondance de modèle à l'aide de méthodes de chaîne:

Utilisez la méthode de chaîne "recherche" pour une recherche insensible à la casse. Lisez à propos de la recherche et des autres méthodes de chaîne sur: 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

Beaucoup de réponses ici, mais j'aime ajouter une sollution 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

Utilisez RegEx pour la correspondance ou la comparaison de chaînes.

En JavaScript, vous pouvez utiliser match()pour la comparaison des chaînes, n'oubliez pas de mettrei dans RegEx.

Exemple:

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

1
Assurez-vous que vous êtes d'accord avec les correspondances partielles, sinon matchString.match(/^test$/i).
hackel

Qu'est-ce qui au lieu de "test" en minuscules vous avez var x = 'test', matchString.match(/x/i)fonctionnerait? Sinon, qu'est-ce qui fonctionnerait?
Razvan Zamfir

3
str = 'Lol', str2 = 'lOl', regex = new RegExp('^' + str + '$', 'i');
if (regex.test(str)) {
    console.log("true");
}

3

Si les deux chaînes sont des mêmes paramètres régionaux connus, vous pouvez utiliser un Intl.Collatorobjet comme celui-ci:

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 le Collatorpour une meilleure efficacité.

Les avantages de cette approche est qu'il devrait être beaucoup plus rapide que d' utiliser des expressions rationnelles et repose sur une très personnalisable (voir description localeset optionsparamètres du constructeur dans l'article ci - dessus) un ensemble de collateurs prêt à l'emploi.


Une autre option pour la sensibilité est accent, ce qui la rend insensible à la casse, mais traite aet en átant que caractères séparés. Donc, baseou accentpourraient tous deux être appropriés en fonction des besoins exacts.
Matthew Crumley

2

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

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

1
Que se passe-t-il deux bases de code avec des idées différentes sur la façon dont String # isEqual devrait fonctionner essayer d'exister en même temps?
Ryan Cavanaugh

3
@KhanSharp Beaucoup de gens le considèrent comme un anti-modèle pour modifier le prototype des types intégrés. C'est pourquoi les gens pourraient voter contre votre réponse.
jt000

1
N'est-il pas inconsidéré de préférer des définitions de méthodes inconnues? Par exemple, dès qu'un navigateur décide d'implémenter String#isEqualou de Object#isEqualmanière native toutes vos pages se comportent différemment et peuvent faire des choses étranges si la spécification ne correspond pas exactement à la vôtre.
Robert

2

Même cette question a déjà répondu. J'ai une approche différente pour utiliser RegExp et match pour ignorer la casse. Veuillez 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);

  }

1

Que diriez-vous de ne PAS lancer d'exceptions et de NE PAS utiliser l'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 correspondre si l'une des chaînes est nulle ou non définie.

Si vous souhaitez 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 d'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());

Ou tout simplementstr1 == str2 || ...
SLaks

1

Puisqu'aucune réponse n'a clairement fourni un simple extrait de code à utiliser 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 undefinedpar exemple, planterait une expression commestr1.toUpperCase() ).
  2. Ne souffre pas d'éventuels problèmes d'internationalisation.
  3. Échappe à la RegExpchaîne.

Mais souffre d'un manque d'évasion d'expression rationnelle.
Qwertiy

@Qwertiy fair point, ajout d'un échappement par stackoverflow.com/a/3561711/67824 .
Ohad Schneider

0

Il s'agit d'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();
    }
}



Utilisations et tests:


0

Convertissez les deux en plus bas (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);
}

Qui a dit que C était mort? : D
Seth

0

Si vous savez que vous avez affaire à ascii texte, vous pouvez simplement utiliser une comparaison de décalage de caractères en majuscules / minuscules.

Assurez-vous simplement que la chaîne de votre chaîne "parfaite" (celle avec laquelle vous voulez faire correspondre) est en minuscules:

const CHARS_IN_BETWEEN = 32;
const LAST_UPPERCASE_CHAR = 90; // Z
function strMatchesIgnoreCase(lowercaseMatch, value) {
    let i = 0, matches = lowercaseMatch.length === value.length;
    while (matches && i < lowercaseMatch.length) {
        const a = lowercaseMatch.charCodeAt(i);
        const A = a - CHARS_IN_BETWEEN;
        const b = value.charCodeAt(i);
        const B = b + ((b > LAST_UPPERCASE_CHAR) ? -CHARS_IN_BETWEEN : CHARS_IN_BETWEEN);
        matches = a === b // lowerA === b
            || A === b // upperA == b
            || a === B // lowerA == ~b
            || A === B; // upperA == ~b
        i++;
    }
    return matches;
}

0

J'aime cette variante abrégée rapide -

export const equalsIgnoreCase = (str1, str2) => {
    return (!str1 && !str2) || (str1 && str2 && str1.toUpperCase() == str2.toUpperCase())
}

Rapide dans le traitement et fait ce à quoi il est destiné.


0

Cette javascript bibliothèque semble fournir beaucoup d'opérations sur les chaînes. C'est très pratique à utiliser

Comment installer

npm install --save string

Importation

var S = require('string');

Ignorecase Compare String

var isEqual = S('ignoreCase').equalsIgnoreCase('IGNORECASE')
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.