Как проверить, содержит ли строка другую строку без учета регистра в Java?

скажем, у меня есть две строки

String s1 = "AbBaCca";
String s2 = "bac";

Я хочу выполнить проверку, возвращая это s2 внутри s1. Я могу сделать это с:

return s1.contains(s2);

я почти уверен, что contains() чувствителен к регистру, однако я не могу точно определить это из чтения документации. Если это так, то я полагаю, что мой лучший метод будет чем-то вроде:

return s1.toLowerCase().contains(s2.toLowerCase());

все это в сторону, есть другой (возможно лучший) способ сделать это, не заботясь о чувствительность к регистру?

17 ответов


да, contains чувствителен к регистру. Вы можете использовать Java.утиль.регулярное выражение.Шаблон с флагом CASE_INSENSITIVE для сопоставления без учета регистра:

Pattern.compile(Pattern.quote(s2), Pattern.CASE_INSENSITIVE).matcher(s1).find();

EDIT: если s2 содержит специальные символы regex (которых много), важно сначала процитировать его. Я исправил свой ответ, так как это первый, который люди увидят, но проголосуйте за Мэтта Куэйла, так как он указал на это.


одна проблема с ответ Дэйва л. - это когда s2 содержит разметку регулярных выражений, такую как \d, etc.

вы хотите вызвать шаблон.цитата() на с2:

Pattern.compile(Pattern.quote(s2), Pattern.CASE_INSENSITIVE).matcher(s1).find();

можно использовать

org.apache.commons.lang3.StringUtils.containsIgnoreCase("AbBaCca", "bac");

на Apache Commons библиотека очень полезна для такого рода вещей. И этот конкретный может быть лучше, чем регулярные выражения, поскольку регулярное выражение всегда дорого с точки зрения производительности.


Более Быстрая Реализация: Использование String.regionMatches()

использование regexp может быть относительно медленным. Он (медлительность) не имеет значения, если вы просто хотите проверить в одном случае. Но если у вас есть массив или коллекция из тысяч или сотен тысяч строк, все может идти довольно медленно.

в представленном ниже решении не используются регулярные выражения и toLowerCase() (который также медленный, потому что он создает другие строки и просто выбрасывает их после проверять.)

решение основывается на строку.regionMatches() метод, который, кажется, неизвестно. Он проверяет, если 2 String регионы совпадают, но важно то, что он также имеет перегрузку с удобным


Да, это достижимо:

String s1 = "abBaCca";
String s2 = "bac";

String s1Lower = s1;

//s1Lower is exact same string, now convert it to lowercase, I left the s1 intact for print purposes if needed

s1Lower = s1Lower.toLowerCase();

String trueStatement = "FALSE!";
if (s1Lower.contains(s2)) {

    //THIS statement will be TRUE
    trueStatement = "TRUE!"
}

return trueStatement;

этот код вернет строку " TRUE!- так же, как и то, что в нем содержались ваши персонажи.


более простым способом сделать это (не беспокоясь о сопоставлении шаблонов) будет преобразование обоих Strings в нижнем регистре:

String foobar = "fooBar";
String bar = "FOO";
if (foobar.toLowerCase().contains(bar.toLowerCase()) {
    System.out.println("It's a match!");
}

можно использовать регулярные выражения и это работает:

boolean found = s1.matches("(?i).*" + s2+ ".*");

вот некоторые Unicode-дружественные, которые вы можете сделать, если вы вытащите ICU4j. Я думаю, что "игнорировать случай" сомнительно для имен методов, потому что, хотя первичные сравнения силы игнорируют случай, он описывается как специфика, зависящая от локали. Но, надеюсь, это зависит от локали так, как пользователь ожидал бы.

public static boolean containsIgnoreCase(String haystack, String needle) {
    return indexOfIgnoreCase(haystack, needle) >= 0;
}

public static int indexOfIgnoreCase(String haystack, String needle) {
    StringSearch stringSearch = new StringSearch(needle, haystack);
    stringSearch.getCollator().setStrength(Collator.PRIMARY);
    return stringSearch.first();
}

Я сделал тест, найдя нечувствительное к регистру совпадение строки. У меня есть вектор из 150 000 объектов со строкой как одно поле и хотел найти подмножество, которое соответствует строке. Я попробовал три метода:--4-->

  1. конвертировать все в нижний регистр

    for (SongInformation song: songs) {
        if (song.artist.toLowerCase().indexOf(pattern.toLowercase() > -1) {
                ...
        }
    }
    
  2. используйте метод String matches ()

    for (SongInformation song: songs) {
        if (song.artist.matches("(?i).*" + pattern + ".*")) {
        ...
        }
    }
    
  3. использовать регулярные выражения

    Pattern p = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE);
    Matcher m = p.matcher("");
    for (SongInformation song: songs) {
        m.reset(song.artist);
        if (m.find()) {
        ...
        }
    }
    

результаты сроки являются:

  • нет попытки совпадения: 20 мс

  • понизить матч: 182 МС

  • совпадений: МС 278

  • регулярное выражение: 65 мс

регулярное выражение выглядит самым быстрым для этого случая использования.


Я не уверен, что ваш основной вопрос здесь, Но да .содержит чувствителен к регистру.


String container = " Case SeNsitive ";
String sub = "sen";
if (rcontains(container, sub)) {
    System.out.println("no case");
}

public static Boolean rcontains(String container, String sub) {

    Boolean b = false;
    for (int a = 0; a < container.length() - sub.length() + 1; a++) {
        //System.out.println(sub + " to " + container.substring(a, a+sub.length()));
        if (sub.equalsIgnoreCase(container.substring(a, a + sub.length()))) {
            b = true;
        }
    }
    return b;
}

в основном, это метод, который принимает две строки. Предполагается, что это не чувствительная к регистру версия contains(). При использовании метода contains вы хотите увидеть, содержится ли одна строка в другой.

этот метод принимает строку, которая является "sub", и проверяет, равна ли она подстрокам строки контейнера, которые равны по длине"sub". Если вы посмотрите на for цикл, вы увидите, что он повторяется в подстроках (это длина "sub") над строкой контейнера.

каждая итерация проверяет, является ли подстрока строки контейнера equalsIgnoreCase суб.


Если вам нужно искать строку ASCII в другой строке ASCII, например URL-адресом, вы найдете мое решение будет лучше. Я протестировал метод icza и мой для скорости, и вот результаты:

  • дело 1 заняло 2788 МС-regionMatches
  • случай 2 занял 1520 МС-мой

код:

public static String lowerCaseAscii(String s) {
    if (s == null)
        return null;

    int len = s.length();
    char[] buf = new char[len];
    s.getChars(0, len, buf, 0);
    for (int i=0; i<len; i++) {
        if (buf[i] >= 'A' && buf[i] <= 'Z')
            buf[i] += 0x20;
    }

    return new String(buf);
}

public static boolean containsIgnoreCaseAscii(String str, String searchStr) {
    return StringUtils.contains(lowerCaseAscii(str), lowerCaseAscii(searchStr));
}

import java.text.Normalizer;

import org.apache.commons.lang3.StringUtils;

public class ContainsIgnoreCase {

    public static void main(String[] args) {

        String in = "   Annulée ";
        String key = "annulee";

        // 100% java
        if (Normalizer.normalize(in, Normalizer.Form.NFD).replaceAll("[\p{InCombiningDiacriticalMarks}]", "").toLowerCase().contains(key)) {
            System.out.println("OK");
        } else {
            System.out.println("KO");
        }

        // use commons.lang lib
        if (StringUtils.containsIgnoreCase(Normalizer.normalize(in, Normalizer.Form.NFD).replaceAll("[\p{InCombiningDiacriticalMarks}]", ""), key)) {
            System.out.println("OK");
        } else {
            System.out.println("KO");
        }

    }

}

String x="abCd";
System.out.println(Pattern.compile("c",Pattern.CASE_INSENSITIVE).matcher(x).find());

вы можете просто сделать что-то вроде этого:

String s1 = "AbBaCca";
String s2 = "bac";
String toLower = s1.toLowerCase();
return toLower.contains(s2);

еще один простой в использовании метод для поиска строки внутри строки-STRING.INDEXOF ()

  String str = new String("Welcome");
  System.out.print("Found Index :" );
  System.out.println(str.indexOf( 'o' ));

Найденный Индекс: 4

www.tutorialspoint.com/java/java_string_indexof.htm


"AbCd".toLowerCase().contains("abcD".toLowerCase())