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

Скажем, у меня две струны,

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

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

return s1.contains(s2);

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

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

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

Думаю, вы ответили на свой вопрос. Я не думаю, что какое-либо из приведенных ниже решений лучше этого. Но они определенно медленнее.

Nikolay Dimitrov 16.10.2014 20:16

Ваше решение проще, чем любое из приведенных в ответах

LobsterMan 16.11.2017 20:06

Ответ, который ищем я и многие здесь, находится в вашем вопросе.

Lalit Fauzdar 03.12.2017 13:25
DrJava would be an extremely easy way to test this when the documentation fails you. Just type a couple of test cases into its Interactions window, and you should find out.
EfForEffort 17.09.2008 23:41

Ваш пример - самый простой, наиболее читаемый и, вероятно, лучший способ сделать это - лучше, чем любой из ответов, которые я вижу.

user1258361 13.08.2019 00:06
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
407
5
404 036
19
Перейти к ответу Данный вопрос помечен как решенный

Ответы 19

Ответ принят как подходящий

Да, содержит с учетом регистра. Вы можете использовать java.util.regex.Pattern с флагом CASE_INSENSITIVE для сопоставления без учета регистра:

Pattern.compile(Pattern.quote(wantedStr), Pattern.CASE_INSENSITIVE).matcher(source).find();

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

Как указано в документации для Pattern.CASE_INSENSITIVE, это работает только для символов ASCII (т.е. «Ä» не будет соответствовать «ä»). Для этого необходимо дополнительно указать флаг UNICODE_CASE.

Philipp Wendler 15.05.2012 18:49

является ли этот подход с использованием Pattern более производительным, чем s1.toLowerCase().contains(s2.toLowerCase())?

Rajat Gupta 09.08.2012 14:24

Первая попытка не сработала, затем я изменил s2 <-> s1, все работает.

Günay Gültekin 09.04.2013 00:17

@ GünayGültekin Это странно. Приведенный код возвращает true и выглядит правильным, но если я переключаю s2 и s1, он возвращает false. Не могли бы вы перепутать свои определения?

Dave L. 09.04.2013 21:01

Требуется ли меньшая производительность, чем toLowerCase ()? Даже в длинных струнах? Если нет, зачем мне его использовать? Этот метод тоже «длинный» для написания. Для меня это выглядит менее читабельным.

xoned 02.09.2013 17:58

@ user01 Я провел анализ скорости. Результаты см. В моем ответе (я также показал более быстрое решение): stackoverflow.com/a/25379180/1705598

icza 19.08.2014 13:15

Использование Pattern.LITERAL будет быстрее, чем Pattern.quote.

Boann 04.11.2014 16:08

Было бы мне более понятно, что происходит, если бы у нас были лучшие имена переменных: Pattern.compile(Pattern.quote(needle), Pattern.CASE_INSENSITIVE).matcher(haystack).find()

John Bowers 19.02.2015 19:16

Правильность @ user01 важнее производительности, и использование toLowerCase даст потенциально неверные результаты (например, при сравнении определенного греческого текста, содержащего букву «сигма», который имеет две строчные формы для одной и той же прописной формы).

Klitos Kyriacou 20.05.2015 12:52

Хотя вы правы в том, что обычно лучше быть правильным, чем быстро, но это не всегда так. Я все еще надеюсь найти что-то быстрое и точное.

Nathan Loyer 22.03.2019 04:00

Вы можете просто преобразовать обе строки в нижний регистр следующим образом: string.toLowerCase (). Contains ("someExampleString" .toLowerCas‌ e ()) ;.

Zia 04.08.2020 07:16

Я не уверен, в чем ваш главный вопрос, но да, .contains чувствителен к регистру.

он спрашивает, как сопоставить строки с учетом регистра.

user14359593 02.01.2021 15:56

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

Вы хотите вызвать Pattern.quote () на s2:

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

Хороший улов, Мэтт. Мне любопытно узнать, какой метод более эффективен - строчные буквы или ваше шаблонное решение. Разве использование шаблона не менее эффективно для одиночного сравнения, но более эффективно для множественных сравнений?

Aaron 18.09.2008 20:55

Метод .toLowerCase (). Contains (), вероятно, будет быстрее в большинстве случаев. Я бы, наверное, предпочел этот стиль и для меньшей сложности.

Matt Quail 19.09.2008 04:09

@AaronFerguson Да, действительно, toLowerCase().contains() быстрее. Я провел некоторый анализ скорости, результаты см. В моем ответе: stackoverflow.com/a/25379180/1705598

icza 19.08.2014 13:16

@MattQuail нет смысла быть быстрее, если он может быть неправильным. Например, греческая заглавная сигма имеет две строчные формы (в зависимости от того, стоит ли она в конце слова или нет), и при попытке сопоставить подстроку без учета регистра, где подстрока заканчивается сигмой, вы можете легко получить неверный результат. полученные результаты.

Klitos Kyriacou 20.05.2015 12:55

Думаю, нам тоже стоит добавить флаг Pattern.UNICODE_CASE. Не могли бы вы это подтвердить?

Thariq Nugrohotomo 20.07.2016 11:55

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

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;

Этот код вернет строку "ИСТИНА!" как выяснилось, что ваши персонажи содержались.

Большой недостаток использования toLowerCase () заключается в том, что результат зависит от текущего Locale. См .: javapapers.com/core-java/…

Adriaan Koster 21.04.2011 17:41

Вопрос на самом деле содержит лучшее решение, поскольку это не подходит для s2, не использующего строчные буквы. Не говоря уже о таких деталях, как то, что этот не компилируется, и если бы он компилировался, он вернул бы строку.

maaartinus 03.10.2014 18:19

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

Более простой способ сделать это (не беспокоясь о сопоставлении с образцом) - преобразовать оба String в нижний регистр:

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

Регистр символов зависит от языка, что означает, что он будет работать на вашем компьютере, но не будет работать для клиента :). см. комментарий @Adriaan Koster.

kroiz 22.07.2012 10:26

@kroiz, это зависит от того, откуда взялась строка. Сравнение "foobar" и "FOO" всегда будет совпадать, однако, если вы сравниваете вводимую пользователем информацию или специфичный для языка контент, то вы правы - разработчик должен быть осторожен.

Phil 23.07.2012 17:28

Вы можете использовать

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

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

Кто-нибудь знает, уважает ли это локаль?

Charles Wood 11.03.2014 22:33

@CharlesWood Он делегирует String.regionMatches, который использует посимвольные преобразования, поэтому нет. Более того, containsIgnoreCase("ß", "ss") возвращает -1, что неверно во всех региональных стандартах (немецкое «диез» с заглавной буквы превращается в «сс».

maaartinus 03.10.2014 18:16

Какой же тогда способ сравнения немецких слов был бы правильным? Кажется, это один язык, который усложняет все способы сравнения строк: P

chomp 24.03.2019 03:13

Кстати: немецкий язык был официально расширен с заглавной буквы ß в 2017 году: de.wikipedia.org/wiki/Gro%C3%9Fes_%C3%9F. На немецкой клавиатуре введите Shift + Alt Gr + ß -> test: ẞ ?

Kawu 23.11.2019 16:12

Точно так же у вас может быть проблема с заглавными буквами / нижним регистром букв с точками и без точек i <-> İ и ı <-> I на турецком языке (например, в Стамбуле) по сравнению со многими нетюркскими языками, использующими на самом деле слегка отличные гласные для прописных / строчных букв. Я <-> я.

stefan123t 12.11.2020 16:43

Вы можете использовать обычные выражения, и он работает:

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

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

  1. Преобразовать все в нижний регистр

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

    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 мсек.

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

Хорошо, что вы поставили тайминг результаты. Все говорят, насколько медленное регулярное выражение, но на самом деле оно очень быстрое, если вам нужно только один раз скомпилировать регулярное выражение.

woot 18.02.2017 19:35

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, вы увидите, что он выполняет итерацию в подстроках (которые являются длиной «подпрограммы») по строке контейнера.

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

в основном это метод, который требует двух строк. Предполагается, что это не чувствительная к регистру версия contains (). при использовании метода contains вы хотите видеть, содержится ли одна строка в другой. этот метод берет строку "sub" и проверяет, равна ли она подстрокам строки контейнера, которые равны по длине "sub". если вы посмотрите на цикл for, вы увидите, что он выполняет итерацию в подстроках (которые являются длиной «подстроки») по строке контейнера. каждая итерация проверяет, совпадает ли подстрока строки контейнера с регистром подстроки.

seth 11.02.2014 22:10

@ Вы, вероятно, должны добавить это к своему ответу.

The Guy with The Hat 11.02.2014 23:33

Это самый медленный метод из когда-либо существовавших ... и он также не подходит для немецкого языка.

maaartinus 03.10.2014 18:28

Вот несколько дружественных к 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();
}

Более быстрое внедрение: использование String.regionMatches()

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

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

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

public static boolean containsIgnoreCase(String src, String what) {
    final int length = what.length();
    if (length == 0)
        return true; // Empty string is contained

    final char firstLo = Character.toLowerCase(what.charAt(0));
    final char firstUp = Character.toUpperCase(what.charAt(0));

    for (int i = src.length() - length; i >= 0; i--) {
        // Quick check before calling the more expensive regionMatches() method:
        final char ch = src.charAt(i);
        if (ch != firstLo && ch != firstUp)
            continue;

        if (src.regionMatches(true, i, what, 0, length))
            return true;
    }

    return false;
}

Анализ скорости

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

Сравниваю 5 методов.

  1. Наш метод containsIgnoreCase ().
  2. Преобразуя обе строки в нижний регистр и вызывая String.contains().
  3. Преобразуя исходную строку в нижний регистр и вызывая String.contains() с предварительно кэшированной подстрокой в ​​нижнем регистре. Это решение уже не так гибко, потому что тестирует предопределенную подстроку.
  4. Используя регулярное выражение (принятый ответ Pattern.compile().matcher().find() ...)
  5. Использование регулярного выражения, но с предварительно созданным и кешированным Pattern. Это решение уже не так гибко, потому что тестирует предопределенную подстроку.

Результаты (вызвав метод 10 миллионов раз):

  1. Наш метод: 670 мс
  2. 2x toLowerCase () и contains (): 2829 мс
  3. 1x toLowerCase () и contains () с кэшированной подстрокой: 2446 мс
  4. Регулярное выражение: 7180 мс
  5. Регулярное выражение с кешированным Pattern: 1845 мс

Результаты в таблице:

                                            RELATIVE SPEED   1/RELATIVE SPEED
 METHOD                          EXEC TIME    TO SLOWEST      TO FASTEST (#1)
------------------------------------------------------------------------------
 1. Using regionMatches()          670 ms       10.7x            1.0x
 2. 2x lowercase+contains         2829 ms        2.5x            4.2x
 3. 1x lowercase+contains cache   2446 ms        2.9x            3.7x
 4. Regexp                        7180 ms        1.0x           10.7x
 5. Regexp+cached pattern         1845 ms        3.9x            2.8x

Наш метод - В 4 раза быстрее по сравнению с нижним регистром и использованием contains(), В 10 раз быстрее по сравнению с использованием регулярных выражений, а также В 3 раза быстрее, даже если Pattern предварительно кэширован (и теряет гибкость проверки произвольной подстроки).


Код теста анализа

Если вам интересно, как проводился анализ, вот полное работающее приложение:

import java.util.regex.Pattern;

public class ContainsAnalysis {

    // Case 1 utilizing String.regionMatches()
    public static boolean containsIgnoreCase(String src, String what) {
        final int length = what.length();
        if (length == 0)
            return true; // Empty string is contained

        final char firstLo = Character.toLowerCase(what.charAt(0));
        final char firstUp = Character.toUpperCase(what.charAt(0));

        for (int i = src.length() - length; i >= 0; i--) {
            // Quick check before calling the more expensive regionMatches()
            // method:
            final char ch = src.charAt(i);
            if (ch != firstLo && ch != firstUp)
                continue;

            if (src.regionMatches(true, i, what, 0, length))
                return true;
        }

        return false;
    }

    // Case 2 with 2x toLowerCase() and contains()
    public static boolean containsConverting(String src, String what) {
        return src.toLowerCase().contains(what.toLowerCase());
    }

    // The cached substring for case 3
    private static final String S = "i am".toLowerCase();

    // Case 3 with pre-cached substring and 1x toLowerCase() and contains()
    public static boolean containsConverting(String src) {
        return src.toLowerCase().contains(S);
    }

    // Case 4 with regexp
    public static boolean containsIgnoreCaseRegexp(String src, String what) {
        return Pattern.compile(Pattern.quote(what), Pattern.CASE_INSENSITIVE)
                    .matcher(src).find();
    }

    // The cached pattern for case 5
    private static final Pattern P = Pattern.compile(
            Pattern.quote("i am"), Pattern.CASE_INSENSITIVE);

    // Case 5 with pre-cached Pattern
    public static boolean containsIgnoreCaseRegexp(String src) {
        return P.matcher(src).find();
    }

    // Main method: perfroms speed analysis on different contains methods
    // (case ignored)
    public static void main(String[] args) throws Exception {
        final String src = "Hi, I am Adam";
        final String what = "i am";

        long start, end;
        final int N = 10_000_000;

        start = System.nanoTime();
        for (int i = 0; i < N; i++)
            containsIgnoreCase(src, what);
        end = System.nanoTime();
        System.out.println("Case 1 took " + ((end - start) / 1000000) + "ms");

        start = System.nanoTime();
        for (int i = 0; i < N; i++)
            containsConverting(src, what);
        end = System.nanoTime();
        System.out.println("Case 2 took " + ((end - start) / 1000000) + "ms");

        start = System.nanoTime();
        for (int i = 0; i < N; i++)
            containsConverting(src);
        end = System.nanoTime();
        System.out.println("Case 3 took " + ((end - start) / 1000000) + "ms");

        start = System.nanoTime();
        for (int i = 0; i < N; i++)
            containsIgnoreCaseRegexp(src, what);
        end = System.nanoTime();
        System.out.println("Case 4 took " + ((end - start) / 1000000) + "ms");

        start = System.nanoTime();
        for (int i = 0; i < N; i++)
            containsIgnoreCaseRegexp(src);
        end = System.nanoTime();
        System.out.println("Case 5 took " + ((end - start) / 1000000) + "ms");
    }

}

+1, но обратите внимание, что он не работает для ß (немецкое острое S; используется для SS с заглавной буквы), а также для некоторых других символов (см. Исходный код String.regionMatches, который пытается оба преобразования).

maaartinus 03.10.2014 18:25

Вы всегда тестируете одни и те же строки, что на самом деле не совсем справедливое сравнение. «Я» всегда находится посередине, что может иметь или не иметь значения для различных методов поиска. Лучше было бы генерировать случайные строки, а также сообщать о скорости, когда подстрока отсутствует.

user458577 12.10.2014 18:11

Это похоже на метод Apache StringUtils: grepcode.com/file/repo1.maven.org/maven2/org.apache.commons/‌…

alain.janinm 25.11.2014 11:18

@ alain.janinm Я не вижу сходства. Единственное, что кажется «близким» к StringUtils.containsIgnoreCase(), это то, что и мое решение, и решение Apache используют метод regionMatches() (в цикле), но даже это не то же самое, что я называю String.regionMatches(), а Apache вызывает CharSequenceUtils.regionMatches().

icza 25.11.2014 11:32

@icza CharSequenceUtils.regionMatches на самом деле просто вызывает String.regionMatches. В любом случае, я хотел дать информацию, что если кто-то уже использует StringUtils lib, он может просто вызвать его, потому что это кажется эффективным способом, как вы доказываете это своим тестом. Если бы я не использовал Apache lib, я бы определенно использовал ваш метод;)

alain.janinm 25.11.2014 14:19

Умная. Есть ли какая-то конкретная причина производительности, по которой вы начинаете поиск src в конце what? Похоже, что наиболее распространенный вариант использования этой функции - поисковый фильтр, и в этом случае есть вероятность, что what будет в начале src.

Martin Devillers 05.08.2015 18:28

@MartinDevillers Я начинаю поиск в конце, чтобы петля могла идти вниз. И я иду вниз, потому что таким образом условие цикла будет короче и эффективнее (по сравнению с 0), а также так, что не потребуется временная переменная для хранения конечной / последней позиции.

icza 05.08.2015 18:52

ОК, спасибо за ответ! Я не совсем уверен, что эти преимущества перевешивают упомянутые мной недостатки, но, по крайней мере, это ясно.

Martin Devillers 06.08.2015 01:07

Готов поспорить, что значительная часть вашего ускорения - это односимвольный тест. Но если вы собираетесь потратить время и силы на это ускорение, вам следует просто использовать вместо этого Бойера – Мура.

Greg Dougherty 18.05.2016 21:34

Вам следует попробовать сравнить движение вверх и движение вниз. Я подозреваю, что соображение производительности, которое поднял Мартин, более важно, чем сравнение с нулем. Я обычно пишу циклы for, инициализирующие две переменные, i, начиная с 0 и двигаясь вверх, и n, устанавливая максимальное значение, чтобы оно сохранялось локально и не извлекалось повторно и не вычислялось откуда бы то ни было. Содержит большинство тех же преимуществ производительности, что и при запуске с max и при переходе к 0 ... ваш стек на несколько байтов длиннее, потому что одна дополнительная локальная переменная - это все.

ArtOfWarfare 11.04.2017 18:02

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

Bill K 07.12.2017 21:56

В моих тестах это было медленным, очень медленно сравнивать взаимодействие по списку на Android с использованием SearchView с реализацией Filter на моем Adapter.

Abner Escócio 26.07.2018 17:28

@icza, можете ли вы добавить apache StringUtils.containsIngnoreCase в свой тестовый пример? Думаю, здесь людям легче понять, что твое быстрее.

Rafael Sanches 17.05.2019 00:29

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

Mugen 16.04.2020 09:30

@Mugen Это решение не преобразует строки в нижний регистр.

icza 16.04.2020 10:41

Если вам нужно искать строку 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));
}

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

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

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

    }

}

Спасибо за этот фрагмент кода, который может предоставить некоторую краткосрочную помощь. Правильное объяснение значительно улучшит его долгосрочной ценности, показывая Почему, это хорошее решение проблемы, которое сделает его более полезным для будущих читателей с другими подобными вопросами. Пожалуйста, редактировать свой ответ, чтобы добавить некоторые пояснения, включая сделанные вами предположения.

Toby Speight 20.02.2018 12:20

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

Можете ли вы улучшить свой ответ, объяснив, как ваш код решает проблему?

Isuka 13.12.2017 10:58

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

DaveyDaveDave 13.12.2017 11:01

Мы можем использовать поток с anyMatch и содержать Java 8

public class Test2 {
    public static void main(String[] args) {

        String a = "Gina Gini Protijayi Soudipta";
        String b = "Gini";

        System.out.println(WordPresentOrNot(a, b));
    }// main

    private static boolean WordPresentOrNot(String a, String b) {
    //contains is case sensitive. That's why change it to upper or lower case. Then check
        // Here we are using stream with anyMatch
        boolean match = Arrays.stream(a.toLowerCase().split(" ")).anyMatch(b.toLowerCase()::contains);
        return match;
    }

}

Существует простой и краткий способ использования флага регулярного выражения (без учета регистра {i}):

 String s1 = "hello abc efg";
 String s2 = "ABC";
 s1.matches(".*(?i)"+s2+".*");

/*
 * .*  denotes every character except line break
 * (?i) denotes case insensitivity flag enabled for s2 (String)
 * */

или вы можете использовать простой подход и просто преобразовать регистр строки в регистр подстроки, а затем использовать метод contains.

Другие вопросы по теме