Избегайте каждого литерала в строке регулярного выражения вместо кавычки всей строки

1

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

Проблема с Pattern.quote заключается в том, что она Pattern.quote строку целиком, а не каждый отдельный символ.

Это мой случай:
Я получаю строку от пользователя и должен искать ее в документе. Поскольку пользователь не может передавать новые строковые символы (это ошибка в стороннем API, к которому у меня нет доступа), я решил обработать любую последовательность пробелов как "\ s+" и использовать регулярное выражение для поиска документа. Таким образом, пользователь может отправлять простые пробелы вместо символа новой строки.

Например, если документ:

Метасимвол \s используется для поиска символа пробела.

Символом пробелов может быть:

Символ пробела
Символ табуляции
Символ возврата каретки Новый символ линии
Вертикальный символ табуляции
Символ подачи формы

Затем полученная строка

String receivedStr = "The \s metacharacter is used to find a whitespace character. A whitespace character can be:";

следует найти в документе.

Чтобы добиться этого, я хочу процитировать строку, а затем заменить любую последовательность пробелов строкой "\ s+".
Используя следующий код:

receivedStr = Pattern.quote(receivedStr).replaceAll("\\s+", "\\\\s+");

выведите регулярное выражение:

\QThe\s+\s\s+ метасимволом \s+ является\s+ используется \s+ в\s+ найти \s+ а\s+ пробел \s+ символов.\s+ A\s+ пробельные \s+ символ\s+ может \s+ будет:\E

что, конечно, проигнорирует мой добавленный "\s+" вместо ожидаемого:

\s+\\s\s+ метасимволом \s+ является\s+ используется \s+ в\s+ найти \s+ а\s+ пробел \s+ символов.\s+ A\s+ пробельные \s+ символ\s+ может \s+ быть:

что только ускользает от "\ s" литерала, а не от всей строки.

Есть ли альтернатива Pattern.quote которая избегает одиночных литералов вместо цельной строки?

Теги:
string
escaping

1 ответ

2
Лучший ответ

Я бы предложил что-то вроде этого:

String re = Stream.of(input.split("\\s+"))
                  .map(Pattern::quote)
                  .collect(Collectors.joining("\\s+"));

Это гарантирует, что все будет процитировано (в том числе материал, который в противном случае будет интерпретироваться как внешний вид и может вызвать экспоненциальное раздутие в поиске совпадений), и любой введенный пользователем пробел заканчивается как \s+.

Пример ввода:

Lorem \\b ipsum \\s dolor (sit) amet.

Вывод:

\QLorem\E\s+\Q\b\E\s+\Qipsum\E\s+\Q\s\E\s+\Qdolor\E\s+\Q(sit)\E\s+\Qamet.\E
  • 0
    Я бы, вероятно, использовал такое решение, хотя мне нужно будет реализовать его версию на Java 7. Спасибо!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню