Como fazer comparação de strings sem distinção entre maiúsculas e minúsculas?

1056

Como executo comparação de strings sem distinção entre maiúsculas e minúsculas em JavaScript?

flybywire
fonte
25
veja o .localeCompare()método javascript recém-adicionado . Suportado apenas por navegadores modernos no momento da gravação (IE11 +). consulte developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/…
Adrien Seja
1
veja também stackoverflow.com/questions/51165/…
Adrien Seja
5
O @AdrienBe "A".localeCompare( "a" );retorna 1no Chrome 48 Console.
Manuell
3
@manuell, o que significa que "a"vem antes "A"quando classificado. Como "a"vem antes "b". Se esse comportamento não for desejado, pode-se querer .toLowerCase()cada letra / sequência. ie "A".toLowerCase().localeCompare( "a".toLowerCase() )consulte developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
Adrien Seja
2
Como comparação é geralmente um termo usado para classificar / ordenar seqüências de caracteres, suponho. Eu comentei aqui há muito tempo agora. ===verificará a igualdade, mas não será bom o suficiente para classificar / ordenar seqüências de caracteres (consulte a pergunta à qual originalmente vinculei).
Adrien Seja

Respostas:

1163

A maneira mais simples de fazer isso (se você não estiver preocupado com caracteres Unicode especiais) é chamar toUpperCase:

var areEqual = string1.toUpperCase() === string2.toUpperCase();
SLaks
fonte
44
A conversão para maiúsculas ou minúsculas fornece comparações corretas sem distinção entre maiúsculas e minúsculas em todos os idiomas. i18nguy.com/unicode/turkish-i18n.html
Samuel Neff
57
@ sam: eu sei. Por isso escrevi if you're not worried about special Unicode characters.
Slaks
141
Existe uma razão para preferir toUpperCasemais toLowerCase?
Jpmc26
19
Isso é realmente o melhor que JS tem a oferecer?
precisa
210

EDIT : Esta resposta foi originalmente adicionada há 9 anos. Hoje você deve usar localeComparecom a sensitivity: 'accent'opção:

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'));

O { sensitivity: 'accent' }comando diz localeCompare()para tratar duas variantes da mesma letra base da mesma, a menos que tenham sotaques diferentes (como no terceiro exemplo) acima.

Como alternativa, você pode usar { sensitivity: 'base' }, que trata dois caracteres como equivalente, desde que o caractere base seja o mesmo (portanto, Aseria tratado como equivalente a á).

Observe que o terceiro parâmetro de localeComparenão é suportado no IE10 ou em navegadores móveis inferiores ou em certos dispositivos (consulte a tabela de compatibilidade na página acima), portanto, se você precisar oferecer suporte a esses navegadores, precisará de algum tipo de fallback:

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  */;
}

Resposta original

A melhor maneira de fazer uma comparação sem distinção entre maiúsculas e minúsculas no JavaScript é usar o match()método RegExp com o isinalizador.

Pesquisa que não diferencia maiúsculas de minúsculas

Quando as duas strings comparadas são variáveis ​​(não constantes), é um pouco mais complicado, porque você precisa gerar um RegExp a partir da string, mas passar a string para o construtor RegExp pode resultar em correspondências incorretas ou falhas na correspondência, se a string possuir regex especial caracteres nele.

Se você se preocupa com a internacionalização, não use toLowerCase()ou toUpperCase()não forneça comparações precisas que não diferenciam maiúsculas de minúsculas em todos os idiomas.

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

Samuel Neff
fonte
5
@ Quandary, sim, foi o que eu disse que tinha que ser tratado - "você precisa gerar um RegExp a partir da string, mas passar a string para o construtor RegExp pode resultar em correspondências incorretas ou falhas, se a string tiver caracteres especiais de regex"
Samuel Neff 06/06
21
Usar essa é a solução mais cara para comparação de strings que não diferencia maiúsculas de minúsculas. Um RegExp destina-se à correspondência complicada de padrões; portanto, ele precisa criar uma árvore de decisão para cada padrão e depois executá-la nas seqüências de entrada. Embora funcione, é comparável a pegar um avião a jato para fazer compras no próximo quarteirão. tl; dr: por favor, não faça isso.
Agoston Horvath
2
Eu poderia usar localeCompare (), mas seu retorno -1 para 'a'.localeCompare('A')e como o op que eu estou procurando caso insensitive string compare.
StingyJack
3
@StingyJack fazer case-insensitive comparar usando localeCompare, você deve fazer 'a'.localeCompare (' A', indefinido, {sensibilidade: 'base'})
Judah Gabriel Himango
1
Nota: A localeCompareversão requer que o motor de JavaScript apoiar a API ECMAScript® Internacionalização , que é não obrigados a fazer. Portanto, antes de confiar nisso, verifique se ele funciona no ambiente que você está usando. Por exemplo: 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 algo assim.
TJ Crowder
46

Como dito em comentários recentes, string::localeComparesuporta comparações sem distinção entre maiúsculas e minúsculas (entre outras coisas poderosas).

Aqui está um exemplo simples

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

E uma função genérica que você poderia usar

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

Observe que, em vez de undefinedvocê provavelmente deve inserir o código do idioma específico com o qual está trabalhando. Isso é importante, conforme indicado nos documentos MDN

em sueco, ä e a são letras base separadas

Opções de sensibilidade

Opções de sensibilidade tabuladas no MDN

Suporte do navegador

No momento da postagem, o UC Browser para Android e Opera Mini não suporta parâmetros de localidade e opções . Verifique https://caniuse.com/#search=localeCompare para obter informações atualizadas.

Jay Wick
fonte
35

Com a ajuda da expressão regular também podemos alcançar.

(/keyword/i).test(source)

/ié para ignorar maiúsculas e minúsculas. Se não for necessário, podemos ignorar e testar a correspondência NÃO sensível a maiúsculas e minúsculas, como

(/keyword/).test(source)
SP007
fonte
17
Usar um regex como esse corresponderá a substrings! No seu exemplo, a string keyWORDirá resultar em uma correspondência positiva. Mas a string this is a keyword yoou keywordstambém resultará em uma correspondência positiva. Esteja ciente de que :-)
Elmer
6
Isso não responde à verificação de igualdade (sem distinção entre maiúsculas e minúsculas), conforme solicitado na pergunta! Mas, este é um cheque Contém ! Não o use #
S.Serpooshan
4
Obviamente, para corresponder à cadeia inteira, o regexp pode ser alterado para /^keyword$/.test(source), mas 1) se keywordnão for uma constante, você precisaria fazer new RegExp('^' + x + '$').test(source)e 2) recorrer a um regexp para testar algo tão simples quanto a igualdade de string sem distinção entre maiúsculas e minúsculas não é muito eficiente.
JHH
28

Lembre-se de que a caixa é uma operação específica do código do idioma. Dependendo do cenário, convém levar isso em consideração. Por exemplo, se você estiver comparando nomes de duas pessoas, considere o código de idioma, mas se estiver comparando valores gerados por máquina, como UUID, talvez não. É por isso que uso a seguinte função na minha biblioteca de utilitários (observe que a verificação de tipo não está incluída por motivos de desempenho).

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
fonte
Existe uma razão para você usar "!!" executar uma conversão booleana explícita, em vez de permitir que a cláusula if avalie a veracidade dos valores?
Celos
Não é necessário. Acho que recebi da minha outra versão do código mais complicado. Eu atualizei a resposta.
Shital Shah 31/03
@thekodester sua função tem um bug. Isso compareStrings("", "")dará falsea despeito do fato das cordas são iguais.
Sergey
@ Sergey Fazendo isso retorna truepara mim. Talvez seja um erro no seu navegador?
Jenna Sloan
14

Recentemente, criei uma micro biblioteca que fornece auxiliares de string que não diferenciam maiúsculas de minúsculas: https://github.com/nickuraltsev/ignore-case . (Ele usa toUpperCaseinternamente.)

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
fonte
12

se você está preocupado com a direção da desigualdade (talvez queira classificar uma lista), é necessário fazer a conversão de maiúsculas e minúsculas e, como existem mais caracteres minúsculos em unicode do que maiúsculas em LowerCase, provavelmente é a melhor conversão a ser usada.

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

O Javascript parece usar o código de idioma "C" para comparações de strings, portanto a ordem resultante será feia se as strings contiverem letras que não sejam ASCII. não há muito que possa ser feito sobre isso sem fazer uma inspeção muito mais detalhada das strings.

Jasen
fonte
7

Suponha que desejamos encontrar a variável string needlena variável string haystack. Existem três dicas:

  1. Aplicativos internacionalizados devem evitar string.toUpperCasee string.toLowerCase. Use uma expressão regular que ignore maiúsculas e minúsculas. Por exemplo, var needleRegExp = new RegExp(needle, "i");seguido por needleRegExp.test(haystack).
  2. Em geral, você pode não saber o valor de needle. Cuidado para needlenão conter caracteres especiais de expressão regular . Fuja deles usando needle.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");.
  3. Em outros casos, se você deseja corresponder com precisão needlee haystack, apenas ignorando o caso, adicione "^"-o no início e "$"no final do construtor de expressões regulares.

Levando em consideração os pontos (1) e (2), um exemplo seria:

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
fonte
Pode apostar! Tudo que você precisa fazer é substituir a new RegExp(...)parte na linha 3 com o seguinte: new RegExp("^" + needle.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&") + "$", "i");. Isso garante que não haja outros caracteres antes ou depois da sua sequência de pesquisa needle.
22716 Chris Chute
4

Existem duas maneiras de comparação sem distinção entre maiúsculas e minúsculas:

  1. Converta seqüências de caracteres em maiúsculas e compare-as usando o operador strict ( ===). Como o operador rigoroso trata os operandos lê o material em: http://www.thesstech.com/javascript/relational-logical-operators
  2. Correspondência de padrões usando métodos de string:

Use o método de string "search" para pesquisa que não diferencia maiúsculas de minúsculas. Leia sobre a pesquisa e outros métodos de string em: 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
fonte
4

Muitas respostas aqui, mas eu gostaria de adicionar uma solução baseada na extensão da biblioteca String:

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

Dessa forma, você pode usá-lo como em Java!

Exemplo:

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");
}

A saída será:

"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");
}

Nebulosar
fonte
4

Use RegEx para correspondência ou comparação de cadeias de caracteres.

Em JavaScript, você pode usar match()para comparação de cadeias, não se esqueça de colocar ino RegEx.

Exemplo:

var matchString = "Test";
if (matchString.match(/test/i)) {
  alert('String matched');
}
else {
 alert('String not matched');
}
Om Sharma
fonte
1
Caso contrário, verifique se você concorda com correspondências parciais matchString.match(/^test$/i).
hackel
O que é, em vez de "teste" em minúsculas, você tem var x = 'test', matchString.match(/x/i)funcionaria? Se não, o que funcionaria?
Razvan Zamfir
3
str = 'Lol', str2 = 'lOl', regex = new RegExp('^' + str + '$', 'i');
if (regex.test(str)) {
    console.log("true");
}
Parth Raval
fonte
3

Se ambas as seqüências de caracteres tiverem o mesmo código de idioma conhecido, convém usar Intl.Collatorobjetos como este:

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

Obviamente, convém armazenar em cache o Collatorpara obter melhor eficiência.

As vantagens dessa abordagem é que ela deve ser muito mais rápida do que usar o RegExps e se baseia em um conjunto extremamente personalizável (veja descrição localese optionsparâmetros do construtor no artigo acima) de separadores prontos para uso.

Alexander Abakumov
fonte
Outra opção para a sensibilidade é accent, que a mantém sem distinção entre maiúsculas e minúsculas, mas trata ae ácomo caracteres separados. Portanto, baseou accentambos podem ser apropriados, dependendo das necessidades exatas.
Matthew Crumley
2

Eu escrevi uma extensão. muito trivial

if (typeof String.prototype.isEqual!= 'function') {
    String.prototype.isEqual = function (str){
        return this.toUpperCase()==str.toUpperCase();
     };
}
Jhankar Mahbub
fonte
1
O que acontece duas bases de código com idéias diferentes de como a String # isEqual deve funcionar tenta existir ao mesmo tempo?
precisa saber é o seguinte
3
@KhanSharp Muitas pessoas consideram um anti-padrão modificar o protótipo de tipos incorporados. É por isso que as pessoas podem votar negativamente na sua resposta.
Jt000
1
Não é mal considerado preferir definições de métodos desconhecidos? Por exemplo, assim que algum navegador decide implementar String#isEqualou Object#isEqualnativamente todas as suas páginas se comportam de maneira diferente e podem fazer coisas estranhas se a especificação não corresponder exatamente à sua.
Robert
2

Até esta pergunta já respondeu. Eu tenho uma abordagem diferente para usar RegExp e corresponder para ignorar maiúsculas de minúsculas. Por favor, veja o meu link 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
fonte
1

Que tal NÃO lançar exceções e NÃO usar regex lento?

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

O snippet acima pressupõe que você não deseja corresponder se uma sequência for nula ou indefinida.

Se você deseja corresponder nulo / indefinido, então:

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

Se, por algum motivo, você se importar com 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
fonte
Ou apenasstr1 == str2 || ...
SLaks
1

Como nenhuma resposta forneceu claramente um trecho de código simples para uso RegExp, eis a minha tentativa:

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

Tem várias vantagens:

  1. Verifica o tipo de parâmetro (qualquer parâmetro que não seja de seqüência de caracteres, como undefinedpor exemplo, trava uma expressão como str1.toUpperCase()).
  2. Não sofre de possíveis problemas de internacionalização.
  3. Escapa a RegExpstring.
Ohad Schneider
fonte
Mas sofre com a falta de regexp escapando.
precisa saber é o seguinte
@Qwertiy fair point, escape adicionado por stackoverflow.com/a/3561711/67824 .
Oade Schneider
0

Esta é uma versão melhorada de esta resposta .

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();
    }
}



Usos e testes:

Sergey
fonte
0

Converta ambos em menor (apenas uma vez por motivos de desempenho) e compare-os com o operador ternário em uma única linha:

function strcasecmp(s1,s2){
    s1=(s1+'').toLowerCase();
    s2=(s2+'').toLowerCase();
    return s1>s2?1:(s1<s2?-1:0);
}
Luca C.
fonte
Quem disse que C está morto? : D
Seth
0

Se você sabe que está lidando com asciitexto, basta usar uma comparação de deslocamento de caracteres em maiúsculas / minúsculas.

Apenas certifique-se de que a string "perfeita" (a que você deseja corresponder) esteja em minúscula:

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
fonte
0

Eu gosto dessa variação rápida de taquigrafia -

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

Rápido no processamento e faz o que se destina.

Neetesh Dadwariya
fonte
0

Essa javascript biblioteca parece fornecer muitas operações de string. É muito conveniente usar

Como instalar

npm install --save string

Importar

var S = require('string');

String de Ignorecase Compare

var isEqual = S('ignoreCase').equalsIgnoreCase('IGNORECASE')
akash
fonte