Como posso tornar minha comparação de strings insensível a maiúsculas e minúsculas?

111

Criei um programa Java para comparar duas strings:

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

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

Ele exibe "bem-vindo". Eu entendo que é sensível a maiúsculas e minúsculas. Mas meu problema é que eu quero comparar duas strings sem distinção entre maiúsculas e minúsculas. Ou seja, espero que a saída seja hai.

user268018
fonte
3
Se você souber que diferencia maiúsculas de minúsculas, poderá converter ambos em minúsculas ou maiúsculas antes de comparar.
fastcodejava de
se você usar, s1.equalsIgnoreCase(s2)poderá falhar em fazê-lo em todos os lugares em que precisa ser feito. Eu sugiro que você descubra de onde vem a string - um arquivo ou banco de dados ou entrada do usuário talvez - e converta para maiúsculas (ou minúsculas) e continue a usar .equals para a comparação.
H2ONaCl
2
Não converta para maiúsculas / minúsculas (como sugerido pelos comentários acima), use a equalsIgnoreCaseabordagem aceita . Leia sobre o problema turco I e questões similares do Unicode para obter a justificativa.
Ohad Schneider
1
@OhadSchneider equalsIgnoreCaseretorna o valor incorreto para turco de qualquer maneira, porque retorna verdadeiro para comparar "i" e "I", embora deva retornar falso. Portanto, suspeito que, se você quiser levar em conta os locais, a Collatoré realmente o caminho a percorrer.
Trejkaz,
1
@OhadSchneider, eu me pergunto. Ele diz que fazer isso por caractere produz o mesmo resultado, mas fazer toLowerCase/ toUpperCaseem toda a string e fazer por caractere também dá dois resultados diferentes.
Trejkaz

Respostas:

171
  • O melhor seria usar s1.equalsIgnoreCase(s2): (ver javadoc )
  • Você também pode convertê-los para maiúsculas / minúsculas e usar s1.equals(s2)
Michael Bavin
fonte
39
Esteja ciente de que as duas soluções não são necessariamente idênticas para todos os locais. String # equalsIgnoreCase não está usando regras de capitalização específicas do local, enquanto String # toLowerCase e #toUpperCase usam.
jarnbjo
1
@jarnbjo Você pode dar um exemplo onde essa diferença?
até
16
Regras de caso específicas de localidade são implementadas pelo menos para turco e alemão. Os turcos tratam I com e sem ponto como duas letras diferentes, criando os pares minúsculos / maiúsculos iİ e ıI, enquanto outros idiomas tratam iI como um par e não usam as letras ı e İ. Em alemão, a minúscula ß é maiúscula como "SS".
jarnbjo
24

String.equalsIgnoreCase é a escolha mais prática para comparação ingênua de strings que não diferencia maiúsculas de minúsculas.

No entanto, é bom estar ciente de que este método não faz a dobragem completa de maiúsculas nem a decomposição e, portanto, não pode realizar a correspondência sem caixa conforme especificado no padrão Unicode. Na verdade, as APIs JDK não fornecem acesso a informações sobre dados de caractere de dobra de caso, portanto, esse trabalho é mais bem delegado a uma biblioteca de terceiros testada e comprovada.

Essa biblioteca é ICU , e aqui está como alguém poderia implementar um utilitário para comparação de strings que não diferencia maiúsculas de 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);

A comparação ingênua com String.equalsIgnoreCaseou String.equalsem strings com letras maiúsculas ou minúsculas irá falhar até mesmo neste teste simples.

(No entanto, observe que o tipo de dobramento de maiúsculas predefinido getNFKCCasefoldInstanceé independente do local; para localidades turcas, um pouco mais de trabalho envolvendo UCharacter.foldCasepode ser necessário.)

glts
fonte
22

Você tem que usar o compareToIgnoreCasemétodo do Stringobjeto.

int compareValue = str1.compareToIgnoreCase(str2);

if (compareValue == 0)isso significa str1igual str2.

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

Agora vai gerar: hai

KNU
fonte
5

Na API Java padrão, você tem:

String.CASE_INSENSITIVE_ORDER

Portanto, você não precisa reescrever um comparador se for usar strings com estruturas de dados classificados.

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

É o que você deseja para verificações de igualdade puras em seu próprio código.

Apenas para maiores informações sobre qualquer coisa relacionada à igualdade de Strings em Java. A função hashCode () da classe java.lang.String "diferencia maiúsculas de 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;
}

Então se você quiser usar um Hashtable / HashMap com Strings como chaves, e ter chaves como "SomeKey", "SOMEKEY" e "Somekey" sejam vistas como iguais, então você terá que embrulhar sua string em outra classe (você não pode estender String, uma vez que é uma classe final). Por exemplo :

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

e então usá-lo como tal:

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

Observe que você pode querer fazer verificações de nulos neles também antes de fazer seu .equals ou .equalsIgnoreCase.

Um objeto String nulo não pode chamar um método equals.

ie:

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
fonte
1
Nota: segundo duas instruções podem ser combinados para produzir o mesmo resultado como este: if (str1 == null || str2 == null) return false;.
LuckyMe
Código modificado para ser mais limpo conforme o comentário acima - foi um longo dia :)
VeenarM
1
Você também pode alterar a primeira linha para a if (str1 == str2) return true;qual ambos atendem a nulos e também atalhos no caso em que as duas referências de string se referem ao mesmo objeto de string.
Barney
1

Para ser nullsafe, você pode usar

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

ou

org.apache.commons.lang3.StringUtils.equalsIgnoreCase(CharSequence, CharSequence)
brandstaetter
fonte
-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
fonte