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 .