Экранирование специальных символов в регулярных выражениях Java - программирование
Подтвердить что ты не робот

Экранирование специальных символов в регулярных выражениях Java

Есть ли какой-либо метод в Java или в любой библиотеке с открытым исходным кодом для экранирования (не цитирования) специального символа (метасимвола), чтобы использовать его как регулярное выражение?

Это было бы очень удобно при динамическом построении регулярного выражения без необходимости вручную удалять каждый отдельный символ.

Например, рассмотрим простое регулярное выражение типа \d+\.\d+, которое соответствует числам с десятичной точкой, например 1.2, а также следующий код:

String digit = "d";
String point = ".";
String regex1 = "\\d+\\.\\d+";
String regex2 = Pattern.quote(digit + "+" + point + digit + "+");

Pattern numbers1 = Pattern.compile(regex1);
Pattern numbers2 = Pattern.compile(regex2);

System.out.println("Regex 1: " + regex1);

if (numbers1.matcher("1.2").matches()) {
    System.out.println("\tMatch");
} else {
    System.out.println("\tNo match");
}

System.out.println("Regex 2: " + regex2);

if (numbers2.matcher("1.2").matches()) {
    System.out.println("\tMatch");
} else {
    System.out.println("\tNo match");
}

Неудивительно, что результат, полученный с помощью вышеуказанного кода:

Regex 1: \d+\.\d+
    Match
Regex 2: \Qd+.d+\E
    No match

То есть regex1 соответствует 1.2, но regex2 (который "динамически" построен) не (вместо этого он соответствует литеральной строке d+.d+).

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

Если бы был, скажем, статический метод escape() в java.util.regex.Pattern, вывод

Pattern.escape('.')

будет строка "\.", но

Pattern.escape(',')

должен просто создать ",", так как это не метасимвол. Аналогично,

Pattern.escape('d')

может генерировать "\d", так как 'd' используется для обозначения цифр (хотя экранирование может не иметь смысла в этом случае, поскольку 'd' может означать буквальный 'd', который не будет неправильно интерпретирован с помощью регулярного выражения быть чем-то другим, как в случае с '.').

4b9b3361

Ответ 1

Есть ли какой-либо метод в Java или любой библиотеке с открытым исходным кодом для экранирования (не цитирования) специального символа (метасимвола), чтобы использовать его как регулярное выражение?

Я не уверен на 100%, это то, о чем вы просите здесь. Если вы ищете способ создания констант, которые вы можете использовать в своих шаблонах регулярных выражений, просто нужно добавить их с помощью "\\" но нет никакой приятной функции Pattern.escape('.') Чтобы помочь в этом.

Поэтому, если вы пытаетесь сопоставить "\\d" (строка \d вместо десятичного символа), вы должны:

// this will match on \d as opposed to a decimal character
String matchBackslashD = "\\\\d";
// as opposed to
String matchDecimalDigit = "\\d";

4 слэша в строке Java превращаются в 2 слэша в шаблоне регулярных выражений. 2 обратная косая черта в шаблоне регулярных выражений совпадает с обратной косой чертой. Превращение любого специального символа с обратным слэшем превращает его в нормальный символ вместо специального.

matchPeriod = "\\.";
matchPlus = "\\+";
matchParens = "\\(\\)";
... 

В вашем сообщении вы используете метод Pattern.quote(string). Вероятно, вы знаете, что это обертывает ваш шаблон между "\\Q" и "\\E" поэтому вы можете сопоставить строку, даже если в ней есть специальный символ регулярного выражения (+, ., \\d и т.д.).

Ответ 2

Я написал этот шаблон:

Pattern SPECIAL_REGEX_CHARS = Pattern.compile("[{}()\\[\\].+*?^$\\\\|]");

И используйте его в этом методе:

String escapeSpecialRegexChars(String str) {

    return SPECIAL_REGEX_CHARS.matcher(str).replaceAll("\\\\$0");
}

Затем вы можете использовать его так, например:

Pattern toSafePattern(String text)
{
    return Pattern.compile(".*" + escapeSpecialRegexChars(text) + ".*");
}

Нам нужно было это сделать, потому что после экранирования мы добавляем некоторые выражения регулярных выражений. Если нет, вы можете просто использовать \Q и \E:

Pattern toSafePattern(String text)
{
    return Pattern.compile(".*\\Q" + text + "\\E.*")
}

Ответ 3

Единственный способ, которым помощник регулярных выражений знает, что вы ищете цифру, а не буква d, - это избежать буквы (\d). Чтобы ввести escape-символ регулярного выражения в java, вам нужно сбежать от него (поэтому \ становится \\). Таким образом, там нет возможности набирать двойные обратные косые черты для специальных символов регулярных выражений.

Ответ 4

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

Ответ 5

использование

pattern.compile("\"");
String s= p.toString()+"yourcontent"+p.toString();

даст результат как yourcontent как есть

Ответ 6

Используйте эту функцию Utility escapeQuotes() для того, чтобы избежать строк между группами и множествами RegualrExpression.

Список литералов Regex для экранирования <([{\^-=$!|]})?*+.>

public class RegexUtils {
    static String escapeChars = "\\.?![]{}()<>*+-=^$|";
    public static String escapeQuotes(String str) {
        if(str != null && str.length() > 0) {
            return str.replaceAll("[\\W]", "\\\\$0"); // \W designates non-word characters
        }
        return "";
    }
}

Из класса Pattern символ обратной косой черты ('\') служит для введения экранированных конструкций. Строковый литерал "\(hello\)" недопустим и приводит к ошибке во время компиляции; чтобы соответствовать строке (привет), необходимо использовать строковый литерал "\\(hello\\)".

Пример: строка для сопоставления (hello) и регулярное выражение с группой (\(hello\)). Форма здесь вам нужно только экранировать совпадающую строку, как показано ниже. Test Regex online

public static void main(String[] args) {
    String matched = "(hello)", regexExpGrup = "(" + escapeQuotes(matched) + ")";
    System.out.println("Regex : "+ regexExpGrup); // (\(hello\))
}

Ответ 7

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

Не существует метода, который делает именно то, что вы ищете, но хорошая новость заключается в том, что на самом деле довольно просто экранировать все специальные символы в регулярном выражении Java:

regex.replaceAll("[\\W]", "\\\\$0")

Почему это работает? Что ж, в документации для Pattern определенно сказано, что допустимо экранировать не алфавитные символы, которые не обязательно должны быть экранированы:

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

Так, например, ; не является специальным символом в регулярном выражении. Однако, если вы избежите этого, Pattern все равно будет интерпретировать \; как ; , Вот еще несколько примеров:

  • > становится \> что эквивалентно >
  • [ становится \[ который является экранированной формой [
  • 8 все еще 8.
  • \) становится \\\) что является экранированными формами \ и ( сцеплено.

Примечание. Ключом является определение "не алфавитного", которое в документации действительно означает "не-словесные" символы или символы вне набора символов [a-zA-Z_0-9].