Рубрики
Без рубрики

Java: Проверьте, содержит ли строка подстроку

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

Автор оригинала: David Landup.

Вступление

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

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

В качестве альтернативы вы можете использовать Apache Commons и вспомогательный класс StringUtils , который предлагает множество производных методов от основных методов для этой цели.

Ядро Java

Строка.содержит()

Первым и основным способом проверки наличия подстроки является метод .contains () . Он предоставляется самим классом String и очень эффективен.

Метод принимает последовательность символов и возвращает true , если последовательность присутствует в строке, на которой мы вызываем метод:

String string = "Java";
String substring = "va";

System.out.println(string.contains(substring));

Запуск этого приведет к:

true

Примечание: Метод .contains() чувствителен к регистру. Если бы мы попытались найти "Va" в нашей строке , результат был бы ложным .

Часто, чтобы избежать этой проблемы, так как мы не ищем чувствительность к регистру, вы бы сопоставили регистр обеих строк перед проверкой:

System.out.println(string.toLowerCase().contains(substring.toLowerCase()));
// OR
System.out.println(string.toUpperCase().contains(substring.toUpperCase()));

Строка.индекс()

Метод .indexOf() немного более грубый, чем метод .contains () , но, тем не менее, это основной механизм, позволяющий методу .contains() работать.

Он возвращает индекс первого вхождения подстроки в строке и предлагает несколько конструкторов на выбор:

indexOf(int ch)
indexOf(int ch, int fromIndex)
indexOf(String str)
indexOf(String str, int fromIndex)

Мы можем либо искать один символ со смещением или без него, либо искать строку со смещением или без него.

Метод вернет индекс первого вхождения, если он присутствует, и -1 если нет:

String string = "Lorem ipsum dolor sit amet.";

// You can also use unicode for characters
System.out.println(string.indexOf('i'));
System.out.println(string.indexOf('i', 8));
System.out.println(string.indexOf("dolor"));
System.out.println(string.indexOf("Lorem", 10));

Запуск этого кода приведет к:

6
19
12
-1
  • Первое вхождение i находится в слове ipsum , в 6 местах от начала последовательности символов.
  • Первое вхождение i со смещением 8 (т. е. поиск начинается с s из ipsum ) находится в поле зрения слово, 19 мест с самого начала.
  • Первое вхождение строки dolor занимает 12 мест с самого начала.
  • И, наконец, нет вхождения Lorem со смещением 10 .

В конечном счете, метод .contains() вызывает метод .indexOf() для работы. Это делает .indexOf() по своей сути еще более эффективным, чем аналог (хотя и в очень небольшом количестве), хотя у него несколько иной вариант использования.

Строка.lastIndexOf()

В отличие от метода .indexOf () , который возвращает первое вхождение, метод .lastIndexOf() возвращает индекс последнего вхождения символа или строки со смещением или без него:

String string = "Lorem ipsum dolor sit amet.";

// You can also use unicode for characters
System.out.println(string.lastIndexOf('i'));
System.out.println(string.lastIndexOf('i', 8));
System.out.println(string.lastIndexOf("dolor"));
System.out.println(string.lastIndexOf("Lorem", 10));

Запуск этого кода приведет к:

19
6
12
0

Некоторые могут быть немного удивлены результатами и сказать:

lastIndexOf('i', 8) должен был вернуться 19 поскольку это последнее вхождение символа после 8-го символа в строке

Что стоит отметить, так это то, что при запуске метода .lastIndexOf() последовательность символов меняется на противоположную. Подсчет начинается с последнего символа и идет к первому.

Как говорится – да. Ожидаемый результат составляет 6 , так как это последнее появление символа после пропуска 8 элементов из конца последовательности.

Шаблон с регулярным выражением и совпадениями

Класс Pattern по сути является скомпилированным представлением регулярного выражения . Он используется вместе с классом Matcher для сопоставления последовательностей символов.

Этот класс работает, сначала составляя шаблон. Затем мы назначаем другой шаблон экземпляру Matcher , который использует метод .find() для сравнения назначенных и скомпилированных шаблонов.

Если они совпадают, метод . find() приводит к true . Если шаблоны не совпадают, метод приводит к false .

Pattern pattern = Pattern.compile(".*" + "some" + ".*");

Matcher matcher = pattern.matcher("Here is some pattern!");
System.out.println(matcher.find());

Это дало бы:

true

Apache Commons

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

Apache Commons предлагает класс StringUtils со множеством вспомогательных методов для обработки строк, проверки на нуль и т. Д. Для этой задачи мы можем использовать любой из методов .contains() , .indexOf() , .lastIndexOf () или .containsIgnoreCase () .

Если нет, включить его так же просто, как добавить зависимость к вашему pom.xml файл, если вы используете Maven:


    org.apache.commons
    commons-lang3
    {version}

Или добавив его через Gradle:

compile group: 'org.apache.commons', name: 'commons-lang3', version: '{version}'

StringUtils.содержит()

Метод .contains() довольно прост и очень похож на основной подход Java.

Единственное отличие состоит в том, что мы не вызываем метод в проверяемой строке (поскольку он не наследует этот метод), а скорее передаем строку, в которой мы ищем, вместе со строкой, которую мы ищем:

String string = "Checking for substrings within a String is a fairly common task in programming.";

System.out.println(StringUtils.contains(string, "common task"));

Запуск этого кода приведет к:

true

Git Essentials

Ознакомьтесь с этим практическим руководством по изучению Git, содержащим лучшие практики и принятые в отрасли стандарты. Прекратите гуглить команды Git и на самом деле изучите это!

Примечание: Этот метод чувствителен к регистру.

StringUtils.indexOf()

Естественно, метод .indexOf() также работает очень похоже на основной подход Java:

String string = "Checking for substrings within a String is a fairly common task in programming.";

// Search for first occurrence of 'f'
System.out.println(StringUtils.indexOf(string, 'f'));

// Search for first occurrence of 'f', skipping the first 12 elements
System.out.println(StringUtils.indexOf(string, 'f', 12));

// Search for the first occurrence of the "String" string
System.out.println(StringUtils.indexOf(string, "String"));

Запуск этого кода приведет к:

9
45
32

StringUtils.indexOfAny()

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

String string = "Checking for substrings within a String is a fairly common task in programming.";

// Search for first occurrence of 'f' or 'n', whichever comes first
System.out.println(StringUtils.indexOfAny(string, ['f', 'n']));

// Search for the first occurrence of "String" or "for", whichever comes first
System.out.println(StringUtils.indexOfAny(string, "String", "for"));

Выполнение этого кода приведет к:

6
9

StringUtils.indexOfAnyBut()

Метод .indexOfAnyBut() ищет первое вхождение любого символа, которого нет в предоставленном наборе:

String string = "Checking for substrings within a String is a fairly common task in programming.";

// Search for first character outside of the provided set 'C' and 'h'
System.out.println(StringUtils.indexOfAny(string, ['C', 'h']));

// Search for first character outside of the provided set 'C' and 'h'
System.out.println(StringUtils.indexOfAny(string, ["Checking", "for"]));

Выполнение этого кода приведет к:

2
14

StringUtils.indexOfDifference()

Метод . indexOfDifference() сравнивает два массива символов и возвращает индекс первого отличающегося символа:

String s1 = "Hello World!"
String s2 = "Hello world!"

System.out.println(StringUtils.indexOfDifference(s1, s2));

Выполнение этого кода приведет к:

6

StringUtils.indexOfIgnoreCase()

Метод .indexOfIgnoreCase() вернет индекс первого вхождения символа в последовательности символов, игнорируя его регистр:

String string = "Checking for substrings within a String is a fairly common task in programming."

System.out.println(StringUtils.indexOf(string, 'c'));
System.out.println(StringUtils.indexOfIgnoreCase(string, 'c'));

Выполнение этого кода приведет к:

3
0

СтрингУтилы.lastIndexOf()

И, наконец, метод .lastIndexOf() работает почти так же, как обычный основной метод Java:

String string = "Lorem ipsum dolor sit amet.";

// You can also use unicode for characters
System.out.println(StringUtils.lastIndexOf(string, 'i'));
System.out.println(StringUtils.lastIndexOf(string, 'i', 8));
System.out.println(StringUtils.lastIndexOf(string, "dolor"));
System.out.println(StringUtils.lastIndexOf(string, "Lorem", 10));

Выполнение этого кода приведет к:

19
6
12
0

StringUtils.containsIgnoreCase()

Метод .containsIgnoreCase() проверяет, содержит ли строка подстроку, игнорируя регистр:

String string = "Checking for substrings within a String is a fairly common task in programming.";

System.out.println(StringUtils.containsIgnoreCase(string, "cOmMOn tAsK"));

Выполнение этого кода приведет к:

true

StringUtils.содержит только()

Метод .содержит только() проверяет, содержит ли последовательность символов только указанные значения.

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

String string = "Hello World!"
System.out.println(StringUtils.containsOnly(string, 'HleWord!'));
System.out.println(StringUtils.containsOnly(string, "wrld"));

Выполнение этого приведет к:

true
false

"Привет, Мир!" Strong действительно состоит только из символов в последовательности " Слово-дыра!" .

Примечание: Не все символы из последовательности необходимо использовать в строке , чтобы метод возвращал значение true. Важно то, что строка не содержит символа, которого нет в последовательности символов.

StringUtils.содержит один()

Метод .не содержит() проверяет, содержит ли строка какие-либо “запрещенные” символы из набора. Если это так, то возвращается false , и наоборот:

String string = "Hello World!"
System.out.println(StringUtils.containsNone(string, 'xmt'));
System.out.println(StringUtils.containsNone(string, "wrld"));

Выполнение этого кода дает:

true
false

StringUtils.содержит много()

И, наконец, метод .containsAny() возвращает true , если последовательность символов содержит какой-либо из переданных параметров в виде последовательности символов или строки:

String string = "Hello World!"
System.out.println(StringUtils.containsAny(string, ['h', 'm']));
System.out.println(StringUtils.containsAny(string, "hell"));

Этот код даст:

true
true

Вывод

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

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