¿Cómo hacer una comparación de cadenas insensible a mayúsculas y minúsculas?

1056

¿Cómo realizo la comparación de cadenas sin distinción entre mayúsculas y minúsculas en JavaScript?

flybywire
fuente
25
vea el .localeCompare()método javascript recién agregado . Solo es compatible con los navegadores modernos en el momento de la escritura (IE11 +). ver developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Adrien Be
1
ver también stackoverflow.com/questions/51165/…
Adrien Be
55
@AdrienBe "A".localeCompare( "a" );regresa 1en la Consola Chrome 48.
manuell
3
@manuell, lo que significa que "a"viene antes "A"cuando se ordena. Como "a"viene antes "b". Si no se desea este comportamiento, uno podría desear .toLowerCase()cada letra / cadena. es decir. "A".toLowerCase().localeCompare( "a".toLowerCase() )ver developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
Adrien Be
2
Porque la comparación es a menudo un término usado para ordenar / ordenar cadenas, supongo. Comenté aquí hace mucho tiempo ahora. ===comprobará la igualdad, pero no será lo suficientemente bueno para ordenar / ordenar cadenas (vea la pregunta que originalmente vinculé).
Adrien Be

Respuestas:

1163

La forma más sencilla de hacerlo (si no le preocupan los caracteres Unicode especiales) es llamar toUpperCase:

var areEqual = string1.toUpperCase() === string2.toUpperCase();
SLaks
fuente
44
La conversión a mayúsculas o minúsculas proporciona comparaciones de mayúsculas y minúsculas correctas en todos los idiomas. i18nguy.com/unicode/turkish-i18n.html
Samuel Neff
57
@ Sam: Lo sé. Por eso escribí if you're not worried about special Unicode characters.
SLaks
141
¿Hay una razón para preferir toUpperCasemás toLowerCase?
jpmc26
19
¿Es esto realmente lo mejor que JS tiene para ofrecer?
Kugel
210

EDITAR : Esta respuesta se agregó originalmente hace 9 años. Hoy deberías usar localeComparecon la sensitivity: 'accent'opción:

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

El { sensitivity: 'accent' }le dice localeCompare()que trate dos variantes de la misma letra base como la misma, a menos que tengan acentos diferentes (como en el tercer ejemplo) anterior.

Alternativamente, puede usar { sensitivity: 'base' }, que trata dos caracteres como equivalentes siempre que su carácter base sea el mismo (por Alo que se trataría como equivalente a á).

Tenga en cuenta que el tercer parámetro de localeCompareno es compatible con IE10 o navegadores móviles inferiores o determinados (consulte la tabla de compatibilidad en la página vinculada anteriormente), por lo que si necesita admitir esos navegadores, necesitará algún tipo de respaldo:

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

Respuesta original

La mejor manera de hacer una comparación entre mayúsculas y minúsculas en JavaScript es usar el match()método RegExp con la ibandera.

Búsqueda sin distinción entre mayúsculas y minúsculas

Cuando ambas cadenas que se comparan son variables (no constantes), entonces es un poco más complicado porque necesita generar un RegExp a partir de la cadena, pero pasar la cadena al constructor RegExp puede resultar en coincidencias incorrectas o fallas si la cadena tiene expresiones regulares especiales personajes en el mismo.

Si le importa la internacionalización, no la use toLowerCase()o toUpperCase()no proporciona comparaciones precisas que no distingan entre mayúsculas y minúsculas en todos los idiomas.

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

Samuel Neff
fuente
55
@Quandary, sí, eso es lo que dije que debía manejarse: "debe generar un RegExp a partir de la cadena, pero pasar la cadena al constructor RegExp puede generar coincidencias incorrectas o coincidencias fallidas si la cadena tiene caracteres especiales de expresión regular".
Samuel Neff
21
Usar esto es la solución más costosa para la comparación de cadenas sin distinción entre mayúsculas y minúsculas. Un RegExp está diseñado para la coincidencia de patrones complicados, por lo tanto, necesita construir un árbol de decisión para cada patrón y luego ejecutarlo contra las cadenas de entrada. Si bien funcionaría, es comparable a tomar un avión a reacción para ir de compras en el siguiente bloque. tl; dr: por favor no hagas esto.
Agoston Horvath
2
podría usar localeCompare (), pero está devolviendo -1 para 'a'.localeCompare('A')y como la operación que estoy buscando.
StingyJack
3
@StingyJack para hacer una comparación entre mayúsculas y minúsculas usando localeCompare, debe hacer 'a'.localeCompare (' A ', indefinido, {sensibilidad:' base '})
Judah Gabriel Himango
1
Nota: La localeCompareversión requiere que el motor de JavaScript compatible con la API ECMAScript® internacionalización , que se no sea requerido. Entonces, antes de confiar en él, es posible que desee comprobar que funciona en el entorno que está utilizando. Por ejemplo: const compareInsensitive = "x".localeCompare("X", undefined, {sensitivity: "base"}) === 0 ? (a, b) => a.localeCompare(b, undefined, {sensitivity: "base"}) : (a, b) => a.toLowerCase().localeCompare(b.toLowerCase());o algo así.
TJ Crowder
47

Como se dijo en comentarios recientes, string::localeCompareadmite comparaciones que no distinguen entre mayúsculas y minúsculas (entre otras cosas poderosas).

Aquí hay un ejemplo simple

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

Y una función genérica que podrías usar

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

Tenga en cuenta que en lugar de undefinedusted probablemente debería ingresar la configuración regional específica con la que está trabajando. Esto es importante como se indica en los documentos de MDN

en sueco, ä y a son letras base separadas

Opciones de sensibilidad

Opciones de sensibilidad tabuladas desde MDN

Soporte del navegador

Al momento de la publicación, UC Browser para Android y Opera Mini no admiten parámetros de configuración regional y opciones . Consulte https://caniuse.com/#search=localeCompare para obtener información actualizada.

Jay Wick
fuente
35

Con la ayuda de la expresión regular también podemos lograr.

(/keyword/i).test(source)

/ies por ignorar caso. Si no es necesario, podemos ignorar y probar NO coincide con mayúsculas y minúsculas como

(/keyword/).test(source)
SP007
fuente
17
¡Usar una expresión regular como esta coincidirá con las subcadenas! En su ejemplo, la cadena keyWORDdará como resultado una coincidencia positiva. Pero la cadena this is a keyword yoo keywordstambién dará como resultado una coincidencia positiva. Tenga en cuenta eso :-)
Elmer
66
¡Esto no responde al control de igualdad (sin distinción entre mayúsculas y minúsculas) como se hizo en la pregunta! Pero, este es un cheque contiene ! No lo use
S.Serpooshan
44
Por supuesto, para que coincida con toda la cadena, la expresión regular se puede cambiar a /^keyword$/.test(source), pero 1) si keywordno es una constante, necesitaría hacer new RegExp('^' + x + '$').test(source)y 2) recurrir a una expresión regular para probar algo tan simple como la igualdad de cadenas sin distinción entre mayúsculas y minúsculas es en absoluto muy eficiente.
JHH
28

Recuerde que la carcasa es una operación específica de la localidad. Dependiendo del escenario, es posible que desee tener eso en cuenta. Por ejemplo, si está comparando los nombres de dos personas, es posible que desee considerar la configuración regional, pero si está comparando valores generados por la máquina, como UUID, es posible que no lo haga. Es por eso que uso la siguiente función en mi biblioteca de utilidades (tenga en cuenta que la verificación de tipos no está incluida por razones de rendimiento).

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
fuente
¿Hay alguna razón por la que usas "!!" realizar una conversión booleana explícita, en lugar de permitir que la cláusula if evalúe la veracidad de los valores?
Celos
No es requerido Supongo que lo tuve de mi otra versión de código más complicado. He actualizado la respuesta.
Shital Shah
@thekodester tu función tiene un error. Esto compareStrings("", "")dará falsea pesar del hecho de que las cuerdas son iguales.
Sergey
@Sergey haciendo eso vuelve truepara mí. Tal vez es un error con su navegador?
Jenna Sloan
14

Recientemente he creado una micro biblioteca que proporciona ayudantes de cadena que no distinguen entre mayúsculas y minúsculas: https://github.com/nickuraltsev/ignore-case . (Se 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
fuente
12

si le preocupa la dirección de la desigualdad (tal vez desee ordenar una lista), prácticamente tiene que hacer una conversión de mayúsculas y minúsculas, ya que hay más caracteres en minúscula en unicode que mayúsculas a LowCase es probablemente la mejor conversión para usar.

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

Javascript parece usar la configuración regional "C" para las comparaciones de cadenas, por lo que el orden resultante será feo si las cadenas contienen letras distintas de ASCII. no se puede hacer mucho al respecto sin hacer una inspección mucho más detallada de las cadenas.

Jasen
fuente
7

Supongamos que queremos encontrar la variable de cadena needleen la variable de cadena haystack. Hay tres trampas:

  1. Las aplicaciones internacionalizadas deben evitarse string.toUpperCasey string.toLowerCase. Utilice una expresión regular que ignore mayúsculas y minúsculas. Por ejemplo, var needleRegExp = new RegExp(needle, "i");seguido de needleRegExp.test(haystack).
  2. En general, es posible que no conozca el valor de needle. Tenga cuidado de que needleno contenga ninguna expresión especial de caracteres especiales . Escapar de estos utilizandoneedle.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); .
  3. En otros casos, si desea hacer coincidir con precisión needley haystack, simplemente ignorando mayúsculas y minúsculas, asegúrese de agregar "^"al comienzo y "$"al final de su constructor de expresiones regulares.

Teniendo en cuenta los puntos (1) y (2), un ejemplo sería:

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
fuente
Usted apuesta! Todo lo que necesita hacer es sustituir la new RegExp(...)parte de la línea 3 por el siguiente: new RegExp("^" + needle.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&") + "$", "i");. Esto asegura que no haya otros caracteres antes o después de su cadena de búsqueda needle.
Chris Chute
4

Hay dos formas de comparación entre mayúsculas y minúsculas:

  1. Convierta cadenas a mayúsculas y luego compárelas usando el operador estricto ( ===). Cómo el operador estricto trata los operandos lee cosas en: http://www.thesstech.com/javascript/relational-logical-operators
  2. Coincidencia de patrones utilizando métodos de cadena:

Utilice el método de cadena "buscar" para la búsqueda sin distinción entre mayúsculas y minúsculas. Lea sobre la búsqueda y otros métodos de cadena en: 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
fuente
4

Muchas respuestas aquí, pero me gusta agregar una solución basada en extender la lib de String:

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

¡De esta manera puedes usarlo como lo haces en Java!

Ejemplo:

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 salida 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
fuente
4

Use RegEx para la coincidencia de cadenas o la comparación.

En JavaScript, puede usar match()para la comparación de cadenas, no olvide poneri RegEx.

Ejemplo:

var matchString = "Test";
if (matchString.match(/test/i)) {
  alert('String matched');
}
else {
 alert('String not matched');
}
Om Sharma
fuente
1
Asegúrese de estar de acuerdo con coincidencias parciales, de lo contrario matchString.match(/^test$/i).
Hackel
¿Qué es en lugar de "prueba" en minúscula que tiene var x = 'prueba', ¿ matchString.match(/x/i)funcionaría? Si no, ¿qué funcionaría?
Razvan Zamfir
3
str = 'Lol', str2 = 'lOl', regex = new RegExp('^' + str + '$', 'i');
if (regex.test(str)) {
    console.log("true");
}
Parth Raval
fuente
3

Si ambas cadenas son de la misma configuración regional conocida, es posible que desee utilizar un Intl.Collatorobjeto como este:

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

Obviamente, es posible que desee almacenar en caché Collatorpara una mejor eficiencia.

Las ventajas de este enfoque es que debería ser mucho más rápido que usar RegExps y se basa en un conjunto extremadamente personalizable (consulte la descripción localesy optionslos parámetros del constructor en el artículo anterior) de los collares listos para usar.

Alexander Abakumov
fuente
Otra opción para la sensibilidad es accent, que lo mantiene sin distinción entre mayúsculas y minúsculas, pero trata ay ácomo caracteres separados. Entonces, baseo accentambos podrían ser apropiados dependiendo de las necesidades exactas.
Matthew Crumley el
2

Escribí una extensión. muy trivial

if (typeof String.prototype.isEqual!= 'function') {
    String.prototype.isEqual = function (str){
        return this.toUpperCase()==str.toUpperCase();
     };
}
Jhankar Mahbub
fuente
1
¿Qué sucede con dos bases de código con ideas diferentes de cómo String # isEqual debería funcionar al tratar de existir al mismo tiempo?
Ryan Cavanaugh
3
@KhanSharp Mucha gente considera que es un antipatrón modificar el prototipo de tipos incorporados. Esta es la razón por la cual la gente podría estar abajo votando su respuesta.
jt000
1
¿No se considera mal preferir definiciones de métodos desconocidos? Por ejemplo, tan pronto como un navegador decida implementar String#isEqualo de Object#isEqualforma nativa, todas sus páginas se comportan de manera diferente y podrían hacer cosas raras si la especificación no coincide exactamente con la suya.
Robert
2

Incluso esta pregunta ya ha respondido. Tengo un enfoque diferente para usar RegExp y coincidir para ignorar mayúsculas y minúsculas. Por favor vea mi enlace 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
fuente
1

¿Qué tal NO lanzar excepciones y NO usar expresiones regulares lentas?

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

El fragmento anterior supone que no desea hacer coincidir si cualquiera de las cadenas es nula o no está definida.

Si desea hacer coincidir nulo / indefinido, entonces:

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

Si por alguna razón te importa indefinido vs nulo:

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
fuente
O simplementestr1 == str2 || ...
SLaks
1

Como ninguna respuesta proporcionó claramente un fragmento de código simple para usar RegExp, este es mi intento:

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

Tiene varias ventajas:

  1. Verifica el tipo de parámetro (cualquier parámetro que no sea de cadena, como undefinedpor ejemplo, bloquearía una expresión como str1.toUpperCase()).
  2. No sufre de posibles problemas de internacionalización.
  3. Se escapa de la RegExpcuerda.
Ohad Schneider
fuente
Pero sufre la falta de escape de expresiones regulares.
Qwertiy
@Qwertiy fair point, escape adicional por stackoverflow.com/a/3561711/67824 .
Ohad Schneider
0

Esta es una versión mejorada de esta respuesta .

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 y pruebas:

Sergey
fuente
0

Convierta ambos a menor (solo una vez por razones de rendimiento) y compárelos con el operador ternario en una sola línea:

function strcasecmp(s1,s2){
    s1=(s1+'').toLowerCase();
    s2=(s2+'').toLowerCase();
    return s1>s2?1:(s1<s2?-1:0);
}
Luca C.
fuente
¿Quién dice que C está muerto? : D
Seth
0

Si sabe que está tratando con asciitexto, puede usar una comparación de desplazamiento de caracteres en mayúsculas / minúsculas.

Solo asegúrese de que la cadena de su cadena "perfecta" (con la que desea hacer coincidir) esté en minúsculas:

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

Me gusta esta variación rápida de taquigrafía:

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

Procesamiento rápido y hace lo que se pretende.

Neetesh Dadwariya
fuente
0

Esta javascript biblioteca parece proporcionar muchas operaciones de cadena. Es muy conveniente de usar

Cómo instalar

npm install --save string

Importar

var S = require('string');

Ignorecase Compare String

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