Разделение строки с escape-последовательностью с использованием регулярного выражения в Java - PullRequest
10 голосов
/ 06 октября 2010

Строка для разделения

abc:def:ghi\:klm:nop

Строка должна быть разделена на ":" «\» является escape-символом. Поэтому «\:» не следует рассматривать как токен.

split (":") дает

[abc]
[def]
[ghi\]
[klm]
[nop]

Обязательный вывод - массив строк

[abc]
[def]
[ghi\:klm]
[nop]

Как можно игнорировать \:

Ответы [ 2 ]

16 голосов
/ 06 октября 2010

Используйте проверочное утверждение :

split("(?<!\\\\):")

Это будет совпадать, только если нет предшествующего \.Использование двойного экранирования \\\\ необходимо, так как один требуется для объявления строки и один для регулярного выражения.

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

string.replaceAll("\\\\\\\\", ESCAPE_BACKSLASH)

(где ESCAPE_BACKSLASH - строка, которая не будет присутствовать в ваших входных данных), а затем, после разбиения с использованием утверждения поиска, заменитьСтрока ESCAPE_BACKSLASH с обратной косой чертой без экранирования с

token.replaceAll(ESCAPE_BACKSLASH, "\\\\")
1 голос
/ 27 января 2016

Гамбо был прав, используя проверочное утверждение , но если ваша строка содержит экранированный escape-символ (например, \\) прямо перед запятой, разделение может прерваться. Смотрите этот пример:

test1\,test1,test2\\,test3\\\,test3\\\\,test4

Если вы выполните простое предварительное разбиение для (?<!\\),, как предложил Гамбо, строка разбивается только на две части test1\,test1 и test2\\,test3\\\,test3\\\\,test4. Это связано с тем, что предварительный просмотр просто проверяет один символ на наличие escape-символа. Что было бы на самом деле правильно, если строка разбита на запятые и запятые, перед которыми стоит четное число escape-символов.

Для достижения этой цели требуется более сложное (двойное) выражение для поиска:

(?<!(?<![^\\]\\(?:\\{2}){0,10})\\),

Используя это более сложное регулярное выражение в Java, снова требуется экранировать все \ на \\. Так что это должен быть более сложный ответ на ваш вопрос:

"any comma separated string".split("(?<!(?<![^\\\\]\\\\(?:\\\\{2}){0,10})\\\\),");

Примечание: Java не поддерживает бесконечные повторения внутри объектов обзора. Поэтому с помощью выражения {0,10} проверяются только до 10 повторяющихся двойных escape-символов. При необходимости вы можете увеличить это значение, отрегулировав последнее число.

...