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

1057

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

fil volant
la source
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
1
voir aussi stackoverflow.com/questions/51165/…
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();
SLaks
la source
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

Samuel Neff
la source
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.

Jay Wick
la source
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)
SP007
la 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;
}
Shital Shah
la source
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
Nick Uraltsev
la source
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.

Jasen
la source
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
}
Chris Chute
la source
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>
Sohail Arif
la source
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");
}

Nébuleuse
la source
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');
}
Om Sharma
la source
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");
}
Parth Raval
la source
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.

Alexander Abakumov
la source
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();
     };
}
Jhankar Mahbub
la source
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);

  }
David S Lee
la source
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());
Ben Wilde
la source
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.
Ohad Schneider
la source
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:

Sergey
la source
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);
}
Luca C.
la source
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;
}
matsko
la source
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é.

Neetesh Dadwariya
la source
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')
akash
la source