У меня есть многострочная строка, которая ограничена набором различных разделителей:
(Text1)(DelimiterA)(Text2)(DelimiterC)(Text3)(DelimiterB)(Text4)
Я могу разделить эту строку на части, используя String.split
, но кажется, что я не могу получить фактическую строку, которая соответствует регулярному выражению разделителя.
Другими словами, это то, что я получаю:
Text1
Text2
Text3
Text4
Это то что я хочу
Text1
DelimiterA
Text2
DelimiterC
Text3
DelimiterB
Text4
Есть ли какой-нибудь способ JDK разбить строку с помощью регулярного выражения-разделителя, но также сохранить разделители?
Ответы:
Вы можете использовать Lookahead и Lookbehind. Как это:
И вы получите:
Последнее, что вы хотите.
((?<=;)|(?=;))
равно выбору пустого символа до;
или после;
.Надеюсь это поможет.
РЕДАКТИРОВАТЬ Фабиан Steeg комментарии на удобочитаемость является действительным. Читаемость всегда является проблемой для RegEx. Одна вещь, которую я делаю, чтобы облегчить это, - создать переменную, имя которой представляет то, что делает регулярное выражение, и использовать формат Java String, чтобы помочь этому. Как это:
Это немного помогает. :-D
источник
split(";", true)
было бы гораздо более читабельным, чемsplit("((?<=;)|(?=;))")
.String.format(WITH_DELIMITER, ";");
как формат является статическим методом.[\\s,]+
которые вы хотите полностью сопоставить. Требуемые регулярные выражения становятся еще длиннее, так как вам нужны дополнительные отрицательные взгляды, чтобы избежать их соответствия в середине, например.(?<=[\\s,]+)(?![\\s,])|(?<![\\s,])(?=[\\s,]+)
,Вы хотите использовать обходные пути и разбивать на совпадения нулевой ширины. Вот некоторые примеры:
И да, это трижды вложенное утверждение в последней модели.
Смежные вопросы
Смотрите также
источник
Очень наивное решение, которое не требует регулярных выражений, заключается в выполнении замены строки в вашем разделителе по типу (при условии использования запятой для разделителя):
Где вы можете заменить тильду (~) соответствующим уникальным разделителем.
Тогда, если вы сделаете разделение на ваш новый разделитель, то я верю, что вы получите желаемый результат.
источник
Мне не очень нравится другой путь, когда вы получаете пустой элемент спереди и сзади. Разделитель обычно находится не в начале или в конце строки, поэтому чаще всего вы тратите два хороших слота массива.
Редактировать: Фиксированный лимит случаев. Закомментированный источник с тестовыми примерами можно найти здесь: http://snippets.dzone.com/posts/show/6453
источник
null
аргумента - правильный путь. Тихая обработка этого приводит к ошибкам, появляющимся позже.Я пришел сюда поздно, но возвращаясь к первоначальному вопросу, почему бы просто не использовать lookarounds?
вывод:
РЕДАКТИРОВАТЬ: То, что вы видите выше, это то, что появляется в командной строке, когда я запускаю этот код, но теперь я вижу, что это немного сбивает с толку. Трудно отследить, какие запятые являются частью результата, а какие были добавлены
Arrays.toString()
. Подсветка синтаксиса SO тоже не помогает. В надежде заставить подсветку работать со мной, а не против меня, вот как будут выглядеть эти массивы, я объявил их в исходном коде:Я надеюсь, что это легче читать. Спасибо за внимание, @finnw.
источник
Я знаю, что это очень-очень старый вопрос, и ответ также был принят. Но все же я хотел бы представить очень простой ответ на оригинальный вопрос. Рассмотрим этот код:
ВЫВОД:
Я просто использую границу слова,
\b
чтобы отделить слова, кроме случаев, когда это начало текста.источник
abcdef
сde
разделителем, но вы можете решить эту проблему с помощью(?!^|$)(?:(?<=de)(?!de)|(?<!de)(?=de))
(?!^|$)
Я посмотрел на приведенные выше ответы и, честно говоря, ни один из них я не нашел удовлетворительным. То, что вы хотите сделать, по сути, имитировать функциональность разделения Perl. Почему в Java это не разрешено и где-то есть метод join (), я не знаю, но я отвлекся. Тебе даже не нужен класс для этого. Это просто функция. Запустите этот пример программы:
Некоторые из более ранних ответов имеют чрезмерную проверку нуля, на которую я недавно написал ответ на вопрос:
https://stackoverflow.com/users/18393/cletus
Во всяком случае, код:
источник
Мне нравится идея StringTokenizer, потому что это Enumerable.
Но он также устарел и заменяется на String.split, который возвращает скучную строку [] (и не включает разделители).
Таким образом, я реализовал StringTokenizerEx, который является Iterable, и который использует истинное регулярное выражение для разделения строки.
Истинное регулярное выражение означает, что это не «последовательность символов», повторяемая для формирования разделителя:
«o» будет соответствовать только «o» и разделит «ooo» на три разделителя с двумя пустыми строками внутри:
Но регулярное выражение o + вернет ожидаемый результат при разбиении "aooob"
Чтобы использовать этот StringTokenizerEx:
Код этого класса доступен на DZone Snippets .
Как обычно для ответа на вызов кода (один автономный класс с включенными тестовыми примерами), скопируйте и вставьте его (в каталог 'src / test') и запустите его . Его метод main () иллюстрирует различные способы использования.
Примечание: (конец 2009 года редактировать)
В статье Заключительные мысли: Java Puzzler: Расщепление Волоски делает хорошую работу explaning причудливое поведение
String.split()
.Джош Блох даже прокомментировал в ответ на эту статью:
Общая библиотека Google Guava содержит также разделитель, который:
Так что, возможно, стоит проверить. Из их исходной грубой документации (pdf) :
источник
Передача 3-го aurgument как "правда". Он также вернет разделители.
источник
Вот простая чистая реализация, которая согласуется
Pattern#split
и работает с шаблонами переменной длины, которые не поддерживаются, и их проще использовать. Это похоже на решение, предоставленное @cletus.Я не делаю нулевых проверок здесь,
Pattern#split
нет, почему я. Мне не нравитсяif
в конце, но это требуется для согласованности сPattern#split
. В противном случае я бы безоговорочно добавил, что привело бы к пустой строке в качестве последнего элемента результата, если входная строка заканчивается шаблоном.Я преобразовываю в String [] для соответствия
Pattern#split
, я использую,new String[0]
а неnew String[result.size()]
, смотрите здесь, почему.Вот мои тесты:
источник
Я также опубликую свои рабочие версии (первая действительно похожа на Markus).
И вот второе решение и его на 50% быстрее, чем первое:
источник
Другой вариант решения с использованием регулярных выражений. Сохраняет порядок токенов, правильно сопоставляет несколько токенов одного типа подряд. Недостатком является то, что регулярное выражение является противным.
Образец вывода:
источник
Я не знаю существующей функции в Java API, которая делает это (что не означает, что она не существует), но вот моя собственная реализация (один или несколько разделителей будут возвращены как один токен; если вы хотите каждый разделитель должен быть возвращен в виде отдельного токена, потребуется немного адаптации):
источник
Я предлагаю использовать Pattern и Matcher, которые почти наверняка достигнут того, что вы хотите. Ваше регулярное выражение должно быть несколько сложнее, чем то, что вы используете в String.split.
источник
Я не думаю, что это возможно с
String#split
, но вы можете использоватьStringTokenizer
, хотя это не позволит вам определить ваш разделитель как регулярное выражение, а только как класс однозначных символов:источник
Если вы можете себе позволить, используйте Java метод replace (цель CharSequence, замена CharSequence) и заполните другой разделитель для разделения. Пример: я хочу разделить строку «boo: and: foo» и оставить строку «:» в правой строке.
Важное примечание: это работает только в том случае, если в вашей строке больше нет «newdelimiter»! Таким образом, это не общее решение. Но если вам известна последовательность CharSequence, в которой вы можете быть уверены, что она никогда не появится в строке, это очень простое решение.
источник
Быстрый ответ: используйте нефизические границы, такие как \ b, чтобы разделить. Я попытаюсь поэкспериментировать, чтобы увидеть, работает ли он (использовал это в PHP и JS).
Возможна и какая-то работа, но может разделиться слишком сильно. На самом деле, это зависит от строки, которую вы хотите разделить, и результата, который вам нужен. Дайте больше подробностей, мы поможем вам лучше.
Другой способ - сделать ваше собственное разделение, захватив разделитель (предположим, что он является переменным) и добавив его позже к результату.
Мой быстрый тест:
Результат:
Слишком много ... :-)
источник
Щипавший Pattern.split () , чтобы включить подходящий шаблон к списку
добавленной
Полный источник
источник
Вот отличная версия, основанная на коде выше, на случай, если это поможет. Во всяком случае, это коротко. Условно включает в себя голову и хвост (если они не пусты). Последняя часть представляет собой демонстрационный пример.
источник
Чрезвычайно наивное и неэффективное решение, которое, тем не менее, работает. Используйте дважды разбитие на строку и затем объедините два массива
источник
источник
Scanner scanner = new Scanner("((A+B)*C-D)*E"); scanner.useDelimiter("((?<=[\\+\\*\\-\\/\\(\\)])|(?=[\\+\\*\\-\\/\\(\\)]))"); while (scanner.hasNext()) { System.out.print(" " + scanner.next()); }
Одна из тонкостей в этом вопросе связана с вопросом «ведущего разделителя»: если у вас будет комбинированный массив токенов и разделителей, вы должны знать, начинается ли он с токена или разделителя. Конечно, вы можете просто предположить, что ведущий разделитель должен быть отброшен, но это кажется неоправданным предположением. Вы также можете узнать, есть ли у вас конечный разделитель или нет. Это устанавливает два логических флага соответственно.
Написано на Groovy, но версия Java должна быть довольно очевидной:
источник
Я не очень хорошо знаю Java, но если вы не можете найти метод Split, который делает это, я предлагаю вам сделать свой собственный.
Это не слишком элегантно, но подойдет.
источник