Как сделать сравнение строк нечувствительным к регистру?

112

Я создал программу на Java для сравнения двух строк:

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

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

Он отображает «добро пожаловать». Я так понимаю, это чувствительно к регистру. Но моя проблема в том, что я хочу сравнить две строки без учета регистра. Т.е. ожидаю на выходе hai.

user268018
источник
3
Если вы знаете, что это чувствительно к регистру, вы можете преобразовать как в нижний, так и в верхний регистр перед сравнением.
fastcodejava
если вы используете, s1.equalsIgnoreCase(s2)вы можете не делать это везде, где это необходимо. Я предлагаю вам найти, откуда берется строка - возможно, из файла, базы данных или пользовательского ввода - и преобразовать ее в верхний (или нижний) регистр и продолжать использовать .equals для сравнения.
H2ONaCl
2
Не конвертируйте в нижний / верхний регистр (как предлагается в комментариях выше), используйте принятый equalsIgnoreCaseподход. Прочтите о проблеме турецкого языка I и аналогичных проблемах с Unicode для обоснования.
Охад Шнайдер
1
@OhadSchneider equalsIgnoreCaseв любом случае возвращает неправильное значение для турецкого языка, потому что он возвращает true для сравнения «i» и «I», даже если он должен возвращать false. Так что я подозреваю, что если вы хотите принять во внимание региональные стандарты, лучше всего использовать a Collator.
Trejkaz 03
1
@OhadSchneider Интересно. Он говорит, что выполнение этого для каждого символа дает тот же результат, но выполнение toLowerCase/ toUpperCaseдля всей строки и выполнение для каждого символа также дает два разных результата.
Trejkaz

Ответы:

172
  • Лучше всего использовать s1.equalsIgnoreCase(s2): (см. Javadoc )
  • Вы также можете преобразовать их в верхний / нижний регистр и использовать s1.equals(s2)
Майкл Бавин
источник
39
Просто имейте в виду, что эти два решения не обязательно идентичны для всех регионов. String # equalsIgnoreCase не использует правила регистра, зависящие от локали, в то время как String # toLowerCase и #toUpperCase используют.
jarnbjo
1
@jarnbjo Не могли бы вы привести пример, где это различие?
Towi
16
По крайней мере, для турецкого и немецкого языков применяются правила для конкретных локалей. Турецкий трактует I с точкой и без нее как две разные буквы, создавая пары нижнего / верхнего регистра iİ и ıI, в то время как другие языки рассматривают iI как пару и не используют буквы ı и İ. В немецком языке нижний регистр ß пишется с заглавной буквы как «SS».
jarnbjo
24

String.equalsIgnoreCase это наиболее практичный выбор для простого сравнения строк без учета регистра.

Однако следует помнить, что этот метод не выполняет ни полного сворачивания, ни декомпозиции, и поэтому не может выполнять сопоставление без регистра, как указано в стандарте Unicode. Фактически, API-интерфейсы JDK не предоставляют доступа к информации о символьных данных сворачивания регистра, поэтому эту работу лучше всего делегировать проверенной сторонней библиотеке.

Это библиотека ICU , и вот как можно реализовать утилиту для сравнения строк без учета регистра:

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

Наивное сравнение с String.equalsIgnoreCase, или String.equalsна прописные или нижний регистр строк не получится даже этот простой тест.

(Обратите внимание, что предопределенный вариант сворачивания регистра не getNFKCCasefoldInstanceзависит от локали; для турецких языков UCharacter.foldCaseможет потребоваться немного больше работы .)

glts
источник
22

Вы должны использовать compareToIgnoreCaseметод Stringобъекта.

int compareValue = str1.compareToIgnoreCase(str2);

if (compareValue == 0)это означает str1равных str2.

Aliti
источник
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");
}

Теперь он выведет: hai

КНУ
источник
5

В Java API по умолчанию у вас есть:

String.CASE_INSENSITIVE_ORDER

Таким образом, вам не нужно переписывать компаратор, если вы использовали строки с сортированными структурами данных.

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

Это то, что вы хотите для проверки чистого равенства в вашем собственном коде.

Просто для получения дополнительной информации обо всем, что касается равенства строк в Java. Функция hashCode () класса java.lang.String "чувствительна к регистру":

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

Поэтому, если вы хотите использовать Hashtable / HashMap со строками в качестве ключей, а такие ключи, как «SomeKey», «SOMEKEY» и «somekey», будут рассматриваться как равные, тогда вам придется обернуть свою строку в другой класс (вы не можете расширить String, поскольку это последний класс). Например :

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

а затем используйте его как таковой:

HashMap<HashWrap, Object> map = new HashMap<HashWrap, Object>();
Ле-Дуд
источник
2

Обратите внимание, что вы также можете выполнить для них нулевую проверку, прежде чем выполнять свои .equals или .equalsIgnoreCase.

Нулевой объект String не может вызывать метод equals.

то есть:

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
источник
1
Примечание: второй два заявления могут быть объединены , чтобы произвести такой же результат , как этот: if (str1 == null || str2 == null) return false;.
LuckyMe
Изменен код, чтобы он был чище, согласно приведенному выше комментарию - был долгий день :)
VeenarM
1
Вы также можете изменить первую строку, if (str1 == str2) return true;которая обслуживает нули, а также сокращает случай, когда две строковые ссылки относятся к одному и тому же строковому объекту.
Barney
1

Чтобы быть нулевым, вы можете использовать

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

или

org.apache.commons.lang3.StringUtils.equalsIgnoreCase(CharSequence, CharSequence)
brandstaetter
источник
-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
источник