Как экранировать текст для регулярного выражения в Java

Есть ли в Java встроенный способ экранирования произвольного текста, чтобы его можно было включить в регулярное выражение? Например, если мои пользователи вводят "5 долларов", я бы хотел, чтобы это совпадало с точным, а не с 5 после окончания ввода.

8 ответов

Решение

Начиная с Java 1.5, да:

Pattern.quote("$5");

Разница между Pattern.quote а также Matcher.quoteReplacement мне было непонятно, прежде чем я увидел следующий пример

s.replaceFirst(Pattern.quote("text to replace"), 
               Matcher.quoteReplacement("replacement text"));

Это может быть слишком поздно, чтобы ответить, но вы также можете использовать Pattern.LITERAL, который будет игнорировать все специальные символы при форматировании:

Pattern.compile(textToFormat, Pattern.LITERAL);

Я думаю, что вы после того, как \Q$5\E, Также см Pattern.quote(s) введено в Java5.

См. Шаблон Javadoc для деталей.

Во-первых, если

  • вы используете replaceAll()
  • Вы НЕ используете Matcher.quoteReplacement()
  • текст для замены включает в себя $1

это не ставит 1 в конце. Он будет смотреть на регулярное выражение поиска для первой подходящей группы и подпункта THAT. Это означает, что $1, $2 или $3 означают в тексте замены: совпадающие группы из шаблона поиска.

Я часто вставляю длинные строки текста в файлы.properties, а затем генерирую из них темы и сообщения электронной почты. Действительно, похоже, что это стандартный способ сделать i18n в Spring Framework. Я помещаю теги XML в качестве заполнителей в строки и использую replaceAll() для замены тегов XML значениями во время выполнения.

Я столкнулся с проблемой, когда пользователь вводил цифру в долларах и центах со знаком доллара. replaceAll() захлебнулся, и в следовой строке появилось следующее:

java.lang.IndexOutOfBoundsException: No group 3
at java.util.regex.Matcher.start(Matcher.java:374)
at java.util.regex.Matcher.appendReplacement(Matcher.java:748)
at java.util.regex.Matcher.replaceAll(Matcher.java:823)
at java.lang.String.replaceAll(String.java:2201)

В этом случае пользователь ввел "$3" где-то в своем вводе, а replaceAll() отправился искать в регулярном выражении поиска третью подходящую группу, не нашел ее и рванул.

Дано:

// "msg" is a string from a .properties file, containing "<userInput />" among other tags
// "userInput" is a String containing the user's input

замена

msg = msg.replaceAll("<userInput \\/>", userInput);

с

msg = msg.replaceAll("<userInput \\/>", Matcher.quoteReplacement(userInput));

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

Чтобы иметь защищенный шаблон, вы можете заменить все символы на "\\\\", кроме цифр и букв. И после этого вы можете вставить в этот защищенный шаблон ваши специальные символы, чтобы этот шаблон работал не как глупый цитируемый текст, а как паттерн, но как ваш собственный. Без специальных символов пользователя.

public class Test {
    public static void main(String[] args) {
        String str = "y z (111)";
        String p1 = "x x (111)";
        String p2 = ".* .* \\(111\\)";

        p1 = escapeRE(p1);

        p1 = p1.replace("x", ".*");

        System.out.println( p1 + "-->" + str.matches(p1) ); 
            //.*\ .*\ \(111\)-->true
        System.out.println( p2 + "-->" + str.matches(p2) ); 
            //.* .* \(111\)-->true
    }

    public static String escapeRE(String str) {
        //Pattern escaper = Pattern.compile("([^a-zA-z0-9])");
        //return escaper.matcher(str).replaceAll("\\\\$1");
        return str.replaceAll("([^a-zA-Z0-9])", "\\\\$1");
    }
}

Pattern.quote("Blabla") работает хорошо.

Pattern.quote() работает хорошо. Он заключает в себе предложение с символами "\ Q" и "\ E", и если он экранирует "\Q" и "\E". Однако, если вам нужно сделать реальное экранирование регулярного выражения (или пользовательское экранирование), вы можете использовать этот код:

String someText = "Some/s/wText*/,**";
System.out.println(someText.replaceAll("[-\\[\\]{}()*+?.,\\\\\\\\^$|#\\\\s]", "\\\\$0"));

Этот метод возвращает: Some / \ s / wText * / \, **

Код для примера и тесты:

String someText = "Some\\E/s/wText*/,**";
System.out.println("Pattern.quote: "+ Pattern.quote(someText));
System.out.println("Full escape: "+someText.replaceAll("[-\\[\\]{}()*+?.,\\\\\\\\^$|#\\\\s]", "\\\\$0"));

Символ ^(отрицание) используется для сопоставления с чем-то, что не входит в группу символов.

Это ссылка на регулярные выражения

Вот информация об изображении об отрицании:

Информация об отрицании

Другие вопросы по тегам