如何在Java中为正则表达式转义文本

如何在Java中为正则表达式转义文本,java,regex,escaping,Java,Regex,Escaping,Java是否有一种内置的方法来转义任意文本,以便可以将其包含在正则表达式中?例如,如果我的用户输入“$5”,我希望精确匹配它,而不是在输入结束后输入“5”。因为: 我想你想要的是\Q$5\E。另请参见Java5中引入的Pattern.quote 有关详细信息,请参见javadoc。在看到以下示例之前,我并不清楚和之间的区别 s.replaceFirst(Pattern.quote("text to replace"), Matcher.quoteReplaceme

Java是否有一种内置的方法来转义任意文本,以便可以将其包含在正则表达式中?例如,如果我的用户输入“$5”,我希望精确匹配它,而不是在输入结束后输入“5”。

因为:


我想你想要的是
\Q$5\E
。另请参见Java5中引入的
Pattern.quote

有关详细信息,请参见javadoc。

在看到以下示例之前,我并不清楚和之间的区别

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

  • 您使用replaceAll()
  • 您不使用Matcher.quoteReplacement()
  • 待替换的文本包括$1
它不会把1放在最后。它将查看第一个匹配组的搜索正则表达式,并将其细分为。这就是$1、$2或$3在替换文本中的含义:匹配搜索模式中的组

我经常将长字符串插入.properties文件,然后从中生成电子邮件主题和正文。实际上,这似乎是在Spring框架中执行i18n的默认方式。我将XML标记作为占位符放入字符串中,并在运行时使用replaceAll()将XML标记替换为值

我遇到了一个问题,用户输入了一个美元和美分的数字,带有美元符号。replaceAll()被阻塞,以下内容显示在stracktrace中:

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”是.properties文件中的字符串,其中包含“”和其他标记
//“userInput”是包含用户输入的字符串
替换

msg = msg.replaceAll("<userInput \\/>", userInput);
msg=msg.replaceAll(“,用户输入);

msg=msg.replaceAll(“,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.LITERAL
,这将在格式化时忽略所有特殊字符:

Pattern.compile(textToFormat, Pattern.LITERAL);
模式。引号(“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"));
^(否定)符号用于匹配不在字符组中的内容

这是到的链接

以下是有关否定的图像信息:


我很好奇这和使用文字标志之间是否有什么区别,因为javadoc说没有嵌入式标志来打开和关闭文字:请注意,只有知道您的输入,才可以使用\Q和\E。Pattern.quote还将处理文本实际包含这些序列的情况。特别是,
Pattern.quote
替换正则表达式搜索字符串中的特殊字符,如.|+()等,以及
Matcher.quoteReplacement
替换替换字符串中的特殊字符,如用于反向引用的\1。我不同意。Pattern.quote用\Q和\E包装其参数。它不会转义特殊字符。Matcher.quoteReplacement(“4$&%$”)生成“4\$&%\$”。它转义特殊字符。换句话说:
quoteReplacement
只关心两个符号
$
\
,例如,这两个符号可以在替换字符串中用作反向引用
$1
\1
。因此,它不能用于转义/引用regex.Awesome。下面是一个示例,我们想用
T$UYO$HI
替换
$Group$
$
符号在模式和替换中都是特殊的:
“$Group$Members.replaceFirst(模式.quote($Group$”),Matcher.quoteReplacement(“T$UYO$HI”)
请注意,这不会转义字符串本身,而是使用
\Q
\E
对其进行包装。这可能会导致意外的结果,例如
Pattern.quote(*.wav”)。replaceAll(“*”,“*”)
将导致
\Q.*.wav\E
,而不是像您可能期望的那样
.*.wav
。我只是想指出,这种转义方法也适用于您随后引入的表达式。这可能令人惊讶。如果执行
鼠标.toUpperCase().replaceAll(“OUS”,“ic”)
操作,它将返回
鼠标
。您不会期望它返回
鼠标
,因为您没有在
ic
上应用
toUpperCase()
。在我的示例中,
replaceAll()
也将
quote()
应用于
*
插入。您必须执行其他操作,可能
.replaceAll(“*”,“\\E.*\\Q”)
会起作用,但这是违反直觉的。@Parameleon:解决相应问题的最佳方法是使用split map mkString方法。.wav.split(“\\”).map(Pattern.quote).mkString(“.”)。r@Paramaleon如果它确实通过添加单个转义来工作,那么您的初始示例仍然无法实现您想要的功能…如果它单独转义字符,它将把
*.wav
转换为正则表达式模式
\*\.wav
,而replaceAll将把它转换为
\.\.wav
,这意味着它将匹配名称由任意数量的句点加上
.wav
组成的文件。如果他们使用了更脆弱的relie实现,那么您很可能需要
replaceAll(“\\*”,“*”)
String someText = "Some/s/wText*/,**";
System.out.println(someText.replaceAll("[-\\[\\]{}()*+?.,\\\\\\\\^$|#\\\\s]", "\\\\$0"));
String someText = "Some\\E/s/wText*/,**";
System.out.println("Pattern.quote: "+ Pattern.quote(someText));
System.out.println("Full escape: "+someText.replaceAll("[-\\[\\]{}()*+?.,\\\\\\\\^$|#\\\\s]", "\\\\$0"));