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


112

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

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

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

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


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может потребоваться немного больше работы .)


22

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

int compareValue = str1.compareToIgnoreCase(str2);

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


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

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)

-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;
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.