转义Java正则表达式中的特殊字符

时间:2012-05-19 10:39:11

标签: java regex escaping

在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.2regex2(“动态”构建)不匹配(相反,它与文字字符串d+.d+匹配)。

那么,是否有一种方法可以自动转义每个正则表达式元字符?

如果有escape()中的静态java.util.regex.Pattern方法,则输出

Pattern.escape('.')

将是字符串"\.",但

Pattern.escape(',')

应该只生成",",因为它不是元字符。类似地,

Pattern.escape('d')

可以生成"\d",因为'd'用于表示数字(虽然在这种情况下转义可能没有意义,因为'd'可能意味着文字'd',这不会不要被正则表达式的插入者误解为其他东西,就像'.'的情况一样。

7 个答案:

答案 0 :(得分:24)

我写了这个模式:

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.*")
}

答案 1 :(得分:23)

  

在Java或任何开源库中是否有任何方法可以转义(不引用)特殊字符(元字符),以便将其用作正则表达式?

我不是百分百肯定这就是你在这里问的问题。如果您正在寻找一种方法来创建可以在正则表达式模式中使用的常量,那么只需将它们与"\\"一起使用就可以了,但是没有很好的Pattern.escape('.')函数可以帮助解决这个问题。

因此,如果您尝试匹配"\\d"(字符串\d而不是小数字符),那么您可以这样做:

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

Java字符串中的4个斜杠在正则表达式模式中变为2个斜杠。正则表达式模式中的2个反斜杠与反斜杠本身匹配。使用反斜杠前置任何特殊字符会将其转换为普通字符而不是特殊字符。

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

在您的帖子中,您使用Pattern.quote(string) method。您可能知道这会将您的模式包装在"\\Q""\\E"之间,因此您可以匹配字符串,即使它恰好有一个特殊的正则表达式字符(+.\\d等。)

答案 2 :(得分:6)

正则表达式匹配器知道您正在寻找数字而不是字母d的唯一方法是逃避字母(\d)。要在java中键入正则表达式转义字符,您需要对其进行转义(因此\变为\\)。因此,没有办法为特殊的正则表达式字符键入双反斜杠。

答案 3 :(得分:1)

同意格雷,因为您可能需要您的模式同时包含litrals(\ [,\ _))和元字符([,])。因此,使用某些实用程序,您应该能够首先转义所有字符,然后您可以添加要在相同模式上添加的元字符。

答案 4 :(得分:0)

使用

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

将结果显示为yourcontent

答案 5 :(得分:0)

使用此实用程序功能escapeQuotes()来转义 Group Sets 之间的字符串RegualrExpression

要逃避<([{\^-=$!|]})?*+.>的正则表达式文字列表

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),带有组的正则表达式为(\(hello\))。在这里,您只需要转义匹配的字符串,如下所示。 Test Regex online

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

答案 6 :(得分:0)

Pattern.quote(String s)可以满足您的需求。但是,它还有一点不足。它实际上并不会转义单个字符,而只是用\Q...\E来包装字符串。

没有一种方法可以完全满足您的需求,但是好消息是,实际上转义Java正则表达式中的所有特殊字符非常简单:

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

为什么这样做?好吧,Pattern的文档特别指出,它可以转义不一定要转义的非字母字符:

  

在任何不表示转义结构的字母字符之前使用反斜杠是一个错误;这些保留用于将来对正则表达式语言的扩展。 在非字母字符之前可以使用反斜杠,而不管该字符是否属于未转义的构造。

例如,;在正则表达式中不是特殊字符。但是,如果您将其转义,Pattern仍会将\;解释为;。这里还有更多示例:

  • >变成\>,相当于>
  • [成为\[的{​​{1}}
  • [仍然是8
  • 8变成\),是\\\)\的转义形式。

注意:关键是“非字母”的定义,它在文档中实际上表示“ non- 单词”字符或该字符之外的字符设置(