¿Cómo hago para que mi comparación de cadenas no distinga entre mayúsculas y minúsculas?

111

Creé un programa Java para comparar dos cadenas:

String s1 = "Hello";
String s2 = "hello";

if (s1.equals(s2)) {
    System.out.println("hai");
} else {
    System.out.println("welcome");
}

Muestra "bienvenida". Entiendo que distingue entre mayúsculas y minúsculas. Pero mi problema es que quiero comparar dos cadenas sin distinción entre mayúsculas y minúsculas. Es decir, espero que la salida sea hai.

user268018
fuente
3
Si sabe que distingue entre mayúsculas y minúsculas, puede convertir ambos a minúsculas o mayúsculas antes de comparar.
fastcodejava
si lo usa, s1.equalsIgnoreCase(s2)es posible que no lo haga en todos los lugares donde sea necesario. Le sugiero que busque de dónde proviene la cadena (un archivo o una base de datos o una entrada de usuario tal vez) y la convierta a mayúsculas (o minúsculas) y continúe usando .equals para la comparación.
H2ONaCl
2
No convierta a minúsculas / mayúsculas (como lo sugieren los comentarios anteriores), use el equalsIgnoreCaseenfoque aceptado . Lea sobre el problema del turco I y problemas similares de Unicode para conocer la justificación.
Ohad Schneider
1
@OhadSchneider equalsIgnoreCasedevuelve el valor incorrecto para turco de todos modos, porque devuelve verdadero para comparar "i" e "I", aunque debería devolver falso. Así que sospecho que si quieres tener en cuenta las configuraciones regionales, a Collatores realmente el camino a seguir.
Trejkaz
1
@OhadSchneider, me pregunto. Dice que hacerlo por carácter produce el mismo resultado, pero hacer toLowerCase/ toUpperCaseen toda la cadena y hacerlo por carácter también da dos resultados diferentes.
Trejkaz

Respuestas:

171
  • Lo mejor sería usar s1.equalsIgnoreCase(s2): (ver javadoc )
  • También puede convertirlos a mayúsculas / minúsculas y usar s1.equals(s2)
Michael Bavin
fuente
39
Solo tenga en cuenta que las dos soluciones no son necesariamente idénticas para todas las configuraciones regionales. String # equalsIgnoreCase no usa reglas de mayúsculas y minúsculas específicas de la configuración regional, mientras que String # toLowerCase y #toUpperCase sí lo hacen.
jarnbjo
1
@jarnbjo ¿Puedes dar un ejemplo de dónde hay esa diferencia?
Towi
16
Las reglas de casos específicas de la configuración regional se implementan al menos para el turco y el alemán. El turco trata a I con y sin punto como dos letras diferentes, creando los pares de minúsculas / mayúsculas iİ e ıI, mientras que otros idiomas tratan iI como un par y no usan las letras ı e İ. En alemán, la ß minúscula se escribe con mayúscula "SS".
jarnbjo
24

String.equalsIgnoreCase es la opción más práctica para la comparación de cadenas ingenua que no distingue entre mayúsculas y minúsculas.

Sin embargo, es bueno tener en cuenta que este método no realiza el plegado completo ni la descomposición de mayúsculas y minúsculas y, por lo tanto , no puede realizar coincidencias sin mayúsculas como se especifica en el estándar Unicode.De hecho, las API de JDK no brindan acceso a información sobre los datos de caracteres de plegado de mayúsculas y minúsculas, por lo que es mejor delegar este trabajo a una biblioteca de terceros probada y comprobada.

Esa biblioteca es ICU , y así es como se podría implementar una utilidad para la comparación de cadenas que no distingue entre mayúsculas y minúsculas:

import com.ibm.icu.text.Normalizer2;

// ...

public static boolean equalsIgnoreCase(CharSequence s, CharSequence t) {
    Normalizer2 normalizer = Normalizer2.getNFKCCasefoldInstance();
    return normalizer.normalize(s).equals(normalizer.normalize(t));
}
    String brook = "flu\u0308ßchen";
    String BROOK = "FLÜSSCHEN";

    assert equalsIgnoreCase(brook, BROOK);

Comparación ingenua con String.equalsIgnoreCase, oString.equals en cadenas mayúsculas o convertidas a mayúsculas fallará incluso esta simple prueba.

(Sin embargo, tenga en cuenta que el tipo de plegado de mayúsculas y minúsculas predefinido getNFKCCasefoldInstancees independiente de la configuración regional; para las configuraciones regionales turcas UCharacter.foldCasepuede ser necesario un poco más de trabajo )

glts
fuente
22

Tienes que usar el compareToIgnoreCasemétodo del Stringobjeto.

int compareValue = str1.compareToIgnoreCase(str2);

if (compareValue == 0)significa str1iguales str2.

Aliti
fuente
10
import java.lang.String; //contains equalsIgnoreCase()
/*
*
*/
String s1 = "Hello";
String s2 = "hello";

if (s1.equalsIgnoreCase(s2)) {
System.out.println("hai");
} else {
System.out.println("welcome");
}

Ahora saldrá: hai

KNU
fuente
5

En la API de Java predeterminada tienes:

String.CASE_INSENSITIVE_ORDER

Por lo tanto, no es necesario que vuelva a escribir un comparador si usa cadenas con estructuras de datos ordenadas.

String s = "some text here";
s.equalsIgnoreCase("Some text here");

Es lo que desea para verificaciones de igualdad pura en su propio código.

Solo para obtener más información sobre cualquier cosa relacionada con la igualdad de cadenas en Java. La función hashCode () de la clase java.lang.String "distingue entre mayúsculas y minúsculas":

public int hashCode() {
    int h = hash;
    if (h == 0 && value.length > 0) {
        char val[] = value;

        for (int i = 0; i < value.length; i++) {
            h = 31 * h + val[i];
        }
        hash = h;
    }
    return h;
}

Por lo tanto, si desea usar una tabla hash / HashMap con cadenas como claves, y las claves como "SomeKey", "SOMEKEY" y "somekey" se consideran iguales, entonces tendrá que envolver su cadena en otra clase (no puede extender String ya que es una clase final). Por ejemplo :

private static class HashWrap {
    private final String value;
    private final int hash;

    public String get() {
        return value;
    }

    private HashWrap(String value) {
        this.value = value;
        String lc = value.toLowerCase();
        this.hash = lc.hashCode();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o instanceof HashWrap) {
            HashWrap that = (HashWrap) o;
            return value.equalsIgnoreCase(that.value);
        } else {
            return false;
        }
    }

    @Override
    public int hashCode() {
        return this.hash;
    }
}

y luego úselo como tal:

HashMap<HashWrap, Object> map = new HashMap<HashWrap, Object>();
le-doude
fuente
2

Tenga en cuenta que es posible que desee realizar comprobaciones nulas en ellos también antes de realizar su .equals o .equalsIgnoreCase.

Un objeto String nulo no puede llamar a un método igual.

es decir:

public boolean areStringsSame(String str1, String str2)
{
    if (str1 == null && str2 == null)
        return true;
    if (str1 == null || str2 == null)
        return false;

    return str1.equalsIgnoreCase(str2);
}
VeenarM
fuente
1
Nota: segundo dos declaraciones se pueden combinar para producir mismo resultado como este: if (str1 == null || str2 == null) return false;.
LuckyMe
Código modificado para ser más limpio según el comentario anterior - fue un día largo :)
VeenarM
1
También puede cambiar la primera línea a la if (str1 == str2) return true;que ambos atienden nulos y también atajos en el caso en que las dos referencias de cadena se refieran al mismo objeto de cadena.
Barney
1

Para ser nullsafe, puede utilizar

org.apache.commons.lang.StringUtils.equalsIgnoreCase(String, String)

o

org.apache.commons.lang3.StringUtils.equalsIgnoreCase(CharSequence, CharSequence)
brandstaetter
fuente
-6
public boolean newEquals(String str1, String str2)
{
    int len = str1.length();
int len1 = str2.length();
if(len==len1)
{
    for(int i=0,j=0;i<str1.length();i++,j++)
    {
        if(str1.charAt(i)!=str2.charAt(j))
        return false;
    }`enter code here`
}
return true;
}
Javacoder
fuente