Поиск подстроки в строке без учета регистра: решение на Java
Быстрый ответ
Если необходимо установить, содержит ли одна строка (String
) другую без учета регистра, можно привести обе строки к нижнему или верхнему регистру с помощью методов toLowerCase()
или toUpperCase()
перед применением contains()
. Альтернативным подходом является использование Pattern
с флагом CASE_INSENSITIVE
:
String str = "Привет Мир!";
String searchStr = "мир";
boolean containsIgnoreCase = str.toLowerCase().contains(searchStr.toLowerCase());
boolean containsRegex = Pattern.compile(Pattern.quote(searchStr), Pattern.CASE_INSENSITIVE).matcher(str).find();
System.out.println("Содержит ли строка, не учитывая регистр: " + containsIgnoreCase);
System.out.println("С использованием Regex регистр также не учитывается: " + containsRegex);
Заметьте, что для сравнения используются методы toLowerCase()
и toUpperCase()
, в то время как Pattern
с CASE_INSENSITIVE
используется для поиска по шаблону.
Полезные инструменты от Apache Commons
Если вас утомляет написание длинных выражений для простых проверок, обратите внимание на инструменты из Apache Commons Lang и воспользуйтесь методом StringUtils.containsIgnoreCase:
boolean containsIgnoreCase = StringUtils.containsIgnoreCase(str, searchStr);
Этот метод сделает вашу работу проще и уменьшит нагрузку на систему, избегая использования ресурсоёмких регулярных выражений. В результате ваш код будет чистым и понятным, особенно если у вас уже есть зависимость от commons.
Эффективная проверка на null
Независимо от того, какой метод вы выбираете, всегда выполняйте проверку строк на null, чтобы не столкнуться с NullPointerException
:
if (str != null && searchStr != null) {
// проведите проверку, не учитывая регистр
}
В качестве альтернативы можно воспользоваться утилитой Apache Commons Lang, которая выполняет все необходимые действия за вас:
boolean containsIgnoreCase = StringUtils.containsIgnoreCase(str, searchStr);
Метод containsIgnoreCase
корректно обрабатывает null
-значения, возвращая false
и не вызывая исключения.
Вопросы производительности
Важно поддерживать "пульс производительности". Приведение строк к одному регистру может быть избыточным, так как это приводит к созданию новых объектов, особенно для длинных строк.
Однако не стоит беспокоиться: использование Pattern
с предварительно скомпилированными шаблонами регулярных выражений поможет вам в тех случаях, когда поиск проводится часто:
Pattern pattern = Pattern.compile(Pattern.quote(searchStr), Pattern.CASE_INSENSITIVE);
boolean containsIgnoreCase = pattern.matcher(str).find();
Метод Pattern.quote()
очень полезен, когда в строке, которую вы ищете, есть специальные символы регулярных выражений, но не забывайте об оптимизации производительности — от него следует отказаться, когда это не обязательно.
Умение работать с Regex, сделайте это самостоятельно!
Если вы предпочитаете работать без сторонних библиотек и не хотите нагружать систему использованием регулярных выражений, вам пригодится метод String.regionMatches
:
public static boolean containsIgnoreCase(String str, String searchStr) {
if (str == null || searchStr == null) return false;
final int length = searchStr.length();
if (length == 0) return true;
for (int i = str.length() – length; i >= 0; i--) {
if (str.regionMatches(true, i, searchStr, 0, length)) {
return true;
}
}
return false;
}
Метод regionMatches
позволяет сравнивать части строки без учета регистра, избегая преобразования всей строки к одному регистру и использования сторонних библиотек.
Визуализация
Представьте, что у нас есть две банки, наполненные буквами различного регистра:
Банка А (🪣): [А, б, в, д, е, ж, ...]
А также маленькая банка "abc", где буквы расположены в произвольном порядке:
Банка B (🥄): [а, б, в]
Метод String.equalsIgnoreCase()
работает следующим образом:
canString.toLowerCase().contains(popCanString.toLowerCase());
Он позволяет найти меньшую банку в большой, независимо от регистра букв:
🪣: [А, б, в, д, е, ж, ...] ищет 🥄: [а, б, в]
Результат: ✅ Найдено
Метод приводит все буквы к одному регистру, что облегчает поиск, и разные комбинации букв уже не смогут его запутать:
🪣: [а, б, в, д, е, ж, ...] также находит 🥄: [а, б, в]
Таким образом, поиск становится простым отслеживанием совпадения формы, не затрудненным разным написанием букв.
Надежный поиск без учета регистра
При создании функциональности поиска без учета регистра важно учитывать длину искомой строки:
- Если строка поиска длинная, возможно пропустить совпадения.
- Если строка поиска короткая, может быть больше ложных срабатываний, чем вы ожидаете.
Также следует учесть частоту и контекст использования операции поиска:
- Для частого использования или трудоемких заданий лучше использовать предварительно скомпилированные шаблоны regex.
- Для менее интенсивных заданий комбинация
toLowerCase()
/toUpperCase()
иcontains()
может быть хорошим компромиссом между простотой и производительностью.
И, конечно же, выбор оптимального подхода в вашем конкретном случае всегда зависит от тестирования производительности.
Полезные материалы
- Как проверить, содержит ли строка другую строку без учета регистра в Java? – Stack Overflow — содержательное обсуждение на Stack Overflow, предлагающее несколько вариантов решения задачи поиска без учета регистра.
- String (Java Platform SE 7) — подробное руководство по методам класса String в Java API.
- Pattern (Java Platform SE 7) — официальное руководство по регулярным выражениям в Java.
- StringUtils (Apache Commons Lang 3.14.0 API) — обзор универсальных инструментов из Apache Commons StringUtils.
- Регулярные выражения в Java – Tutorial — детальное руководство по регулярным выражениям в Java.