Перейти к основному содержимому

Разделите строку в Java и сохраните разделители

· 5 мин. чтения

Задача: Наибольшая подстрока без повторений

Для заданной строки s, найдите длину наибольшей подстроки без повторяющихся символов. Подстрока — это непрерывная непустая последовательность символов внутри строки...

ANDROMEDA 42

1. Введение

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

Давайте подробно обсудим различные доступные решения этой проблемы разделения строк .

2. Основы

Вселенная Java предлагает довольно много библиотек ( например, java.lang.String , Guava и Apache Commons), облегчающих разбиение строк в простых и довольно сложных случаях. Кроме того, многофункциональные регулярные выражения обеспечивают дополнительную гибкость при разделении задач, связанных с сопоставлением определенного шаблона.

3. Обзорные утверждения

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

Предварительное утверждение Java(?=ForEach) соответствует «Java» , только если за ним следует «ForEach» .

Аналогично, отрицательное утверждение просмотра назад (?<!#)\d+ соответствует числу, только если ему не предшествует '#'.

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

Во всех примерах, объясненных в этой статье, мы будем использовать два простых String :

String text = "Hello@World@This@Is@A@Java@Program";
String textMixed = "@HelloWorld@This:Is@A#Java#Program";

4. Использование String.split()

Начнем с использования метода split() из класса String основной библиотеки Java.

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

4.1. Положительный прогноз

Прежде всего, давайте воспользуемся опережающей проверкой «(( ?=@ ))» и разобьем текст строки вокруг его совпадений:

String[] splits = text.split("((?=@))");

Упреждающее регулярное выражение разбивает строку на прямое совпадение символа «@» . Содержимое результирующего массива:

[Hello, @World, @This, @Is, @A, @Java, @Program]

Использование этого регулярного выражения не возвращает разделители отдельно в массиве splits . Давайте попробуем альтернативный подход.

4.2. Положительный взгляд назад

Мы также можем использовать положительное утверждение обратного просмотра «((?< =@ ))» , чтобы разделить текст строки :

String[] splits = text.split("((?<=@))");

Однако результирующий вывод по-прежнему не будет содержать разделители как отдельные элементы массива:

[Hello@, World@, This@, Is@, A@, Java@, Program]

4.3. Положительный просмотр вперед или просмотр назад

Мы можем использовать комбинацию двух объясненных выше обходов с логическим ИЛИ и увидеть его в действии.

Полученное регулярное выражение «(( ?=@ )|(?< =@ ))» определенно даст нам желаемые результаты. Приведенный ниже фрагмент кода демонстрирует это:

String[] splits = text.split("((?=@)|(?<=@))");

Приведенное выше регулярное выражение разбивает строку, и результирующий массив содержит разделители:

[Hello, @, World, @, This, @, Is, @, A, @, Java, @, Program]

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

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

String[] splitsMixed = textMixed.split("((?=:|#|@)|(?<=:|#|@))");

Было бы неудивительно увидеть следующие результаты после выполнения приведенной выше строки кода:

[@, HelloWorld, @, This, :, Is, @, A, #, Java, #, Program]

5. Использование разделителя гуавы

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

Класс Splitter из Guava предлагает методы on() и onPattern() для разделения строки с использованием шаблона регулярного выражения в качестве разделителя.

Для начала давайте посмотрим, как они работают со строковым текстом , содержащим один разделитель «@» :

List<String> splits = Splitter.onPattern("((?=@)|(?<=@))").splitToList(text);
List<String> splits2 = Splitter.on(Pattern.compile("((?=@)|(?<=@))")).splitToList(text);

Результаты выполнения приведенных выше строк кода очень похожи на результаты, сгенерированные методом split , за исключением того, что теперь у нас есть List вместо массивов.

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

List<String> splitsMixed = Splitter.onPattern("((?=:|#|@)|(?<=:|#|@))").splitToList(textMixed);
List<String> splitsMixed2 = Splitter.on(Pattern.compile("((?=:|#|@)|(?<=:|#|@))")).splitToList(textMixed);

Как мы видим, разница между двумя вышеуказанными способами весьма заметна.

Метод on() принимает аргумент java.util.regex.Pattern , тогда как метод onPattern() просто принимает регулярное выражение-разделитель как String .

6. Использование Apache Commons StringUtils

Мы также можем воспользоваться методом StringUtils проекта Apache Commons Lang splitByCharacterType().

Очень важно отметить, что этот метод работает, разбивая входную строку по типу символа, возвращаемому java.lang.Character.getType(char) . Здесь мы не можем выбирать или извлекать разделители по нашему выбору. ``

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

String[] splits = StringUtils.splitByCharacterType("pg@no;10@hello;world@this;is@a#10words;Java#Program");

Различные типы символов, как показано в приведенной выше строке, — это прописные и строчные буквы, цифры и специальные символы (@ ; # ).

Следовательно, результирующий массив разбивается, как и ожидалось, выглядит так:

[pg, @, no, ;, 10, @, hello, ;, world, @, this, ;, is, @, a, #, 10, words, ;, J, ava, #, P, rogram]

7. Заключение

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

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

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

Как всегда, код, использованный в этой статье, можно найти на GitHub .