Javaで正規表現のテキストをエスケープする方法


320

Javaには、正規表現に含めることができるように、任意のテキストをエスケープする組み込みの方法がありますか?たとえば、ユーザーが「$ 5」と入力した場合、入力の終了後は「5」ではなく、正確に一致させたいと思います。

回答:


450

Java 1.5以降、はい

Pattern.quote("$5");

88
これは文字列自体をエスケープするのではなく、\Qand を使用してラップすることに注意してください\E。これにより、予期しない結果Pattern.quote("*.wav").replaceAll("*",".*")が生じる可能性があります。たとえば、予想どおりに、では\Q.*.wav\Eなく.*\.wavが発生します。
Matthias Ronge 2013年

11
@Paramaeleonなぜfoo(x).bar()== x.bar()だと思いますか?
マイケル

7
@Paramaeleonユースケースを誤解していると思います。
vikingsteve 2013年

18
このエスケープの方法は、後で紹介する式にもエスケープが適用されることを指摘しておきたいと思います。これは意外かもしれません。あなたがそうするなら、"mouse".toUpperCase().replaceAll("OUS","ic")それは戻りMicEます。にMICE申請toUpperCase()しなかったので、あなたはそれが戻ることを期待しないでしょうic。私の例でquote()は、.*インセットにも適用されてreplaceAll()います。他のことをしなければならない、おそらく.replaceAll("*","\\E.*\\Q")うまくいくでしょうが、それは直観に反しています。
Matthias Ronge 2013年

2
それは個々のエスケープを追加することで仕事をした場合は、あなたの最初の例では、まだあなたが望ん@Paramaleonしないだろう、それは個別の文字をエスケープした場合...、それが有効になり*.wav、正規表現パターンに\*\.wav、とでReplaceAllはにそれを回すだろう\.*\.wav、それを考え意味名前が任意の数のピリオドとそれに続くで構成されるファイルに一致します.wav。可能性のあるreplaceAll("\\*", ".*")すべてのアクティブな正規表現の文字を認識して個別にエスケープすることに依存する、より脆弱な実装に彼らが行ったかどうかが必要になる可能性が最も高いでしょう...それははるかに簡単でしょうか?
セオドアマードック

112

次の例を見る前に、Pattern.quoteとの違いがMatcher.quoteReplacementはっきりしなかった

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

29
具体的にPattern.quoteは、。| +()などの正規表現検索文字列のMatcher.quoteReplacement特殊文字を置き換え、後方参照用の\ 1などの置換文字列の特殊文字を置き換えます。
スティーブン

9
同意しません。Pattern.quoteは引数を\ Qと\ Eで囲みます。特殊文字はエスケープしません。
David Medinets、2015

5
Matcher.quoteReplacement( "4 $&%$")は "4 \ $&%\ $"を生成します。特殊文字をエスケープします。
David Medinets、2015

4
言い換えるとquoteReplacement、2つの記号のみを考慮し、たとえば、置換文字列で後方参照またはとして使用できます。したがって、正規表現をエスケープ/引用するために使用してはなりません。$\ $1\1
SebastianH

1
驚くばかり。ここでは、置換する例である$Group$T$UYO$HI$シンボルパターンおよび置換の両方で特別である:"$Group$ Members".replaceFirst(Pattern.quote("$Group$"), Matcher.quoteReplacement("T$UYO$HI"))
アルン

29

応答するには遅すぎるかもしれませんがPattern.LITERAL、フォーマット中にすべての特殊文字を無視するを使用することもできます。

Pattern.compile(textToFormat, Pattern.LITERAL);

それを組み合わせることができるので、それは特に素晴らしいですPattern.CASE_INSENSITIVE
mjjaniec

13

あなたが求めているのはだと思います\Q$5\EPattern.quote(s)Java5で導入されたも参照してください。

詳細については、パターン javadocを参照してください。


これとLITERALフラグの使用に違いがあるかどうか知りたいのですが、javadocはLITERALのオンとオフを切り替える埋め込みフラグがないとしています:java.sun.com/j2se/1.5.0/docs/api/java/ util / regex /…
Chris Mazzola、

15
文字通り\ Qと\ Eを使用しても問題ないことに注意してください。Pattern.quote(s)は、テキストに実際にこれらのシーケンスが含まれている場合も処理します。
Jeremy Huiskamp、2011

10

まず、

  • replaceAll()を使用する
  • Matcher.quoteReplacement()を使用しないでください
  • 置換されるテキストには$ 1が含まれます

最後に1を付けません。最初に一致するグループとサブTHATの検索正規表現を調べます。置換テキストで$ 1、$ 2、または$ 3が意味するのは、検索パターンの一致するグループです。

テキストの長い文字列を.propertiesファイルに頻繁に挿入し、それらからメールの件名と本文を生成します。実際、これはSpring Frameworkで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()は3番目に一致するグループの検索正規表現を探しに行きましたが、見つからず、pukedしました。

与えられた:

// "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));

問題を解決しました。ユーザーは、ドル記号を含むあらゆる種類の文字を問題なく入力できました。期待通りの動作をしました。


6

パターンを保護するには、数字と文字を除くすべての記号を「\\\\」に置き換えます。その後、その保護されたパターンに特別なシンボルを配置して、このパターンを愚かな引用テキストのようではなく、実際にはパッテンのように機能させることができます。ユーザーの特殊記号なし。

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");
    }
}

スペースをエスケープする必要はありません。したがって、パターンを "([^ a-zA-z0-9])"に変更できます。
Erel Segal-Halevi 2013

5
小さなタイプミス、大きな影響:「([^ a-zA-z0-9])」も一致しない(つまり、エスケープしない)[、\、]、^確かにエスケープしたい!タイプミスは2番目の「z」であり、「Z」でなければなりません。それ以外の場合は、ASCII 65からASCII 122までのすべてが含まれます
Zefiro

3

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"));

-2

^(否定)記号は、文字グループに含まれないものに一致させるために使用されます。

これは正規表現へのリンクです

ここに否定についての画像情報があります:

否定についての情報

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.