1. 概要

Javaの正規表現APIであるjava.util.regexは、パターンマッチングに広く使用されています。 詳細については、この記事をフォローしてください。

この記事では、正規表現を使用して文字をエスケープすることに焦点を当て、Javaでそれを実行する方法を示します。

2. 特別な正規表現文字

Java正規表現APIのドキュメントによると、正規表現にはメタ文字とも呼ばれる特殊文字のセットがあります。

文字を特別な意味で解釈するのではなく、そのまま許可したい場合は、エスケープする必要があります。 これらの文字をエスケープすることにより、文字列を特定の正規表現と照合するときに、通常の文字として扱われるように強制します。

通常、この方法でエスケープする必要があるメタ文字は次のとおりです。

<([{\ ^-= $!|]})?*+。>

入力Stringを正規表現で表現されたパターンと照合する簡単なコード例を見てみましょう。

このテストは、パターン foo の場合、特定の入力文字列foofに対してそれを示しています。 (ドット文字で終わる foo )が一致すると、一致が成功したことを示すtrueの値が返されます。

@Test
public void givenRegexWithDot_whenMatchingStr_thenMatches() {
    String strInput = "foof";
    String strRegex = "foo.";
      
    assertEquals(true, strInput.matches(strRegex));
}

入力文字列にドット(。)文字がないのに、なぜ一致が成功するのか不思議に思うかもしれません。

答えは簡単です。 ドット(。)はメタ文字です。ここでのドットの特別な意味は、その場所に「任意の文字」が存在する可能性があることです。 したがって、一致が見つかったとマッチャーがどのように判断したかは明らかです。

ドット(。)文字をその固有の意味で扱いたくないとしましょう。 代わりに、ドット記号として解釈されるようにします。 これは、前の例では、パターンを許可したくないことを意味します foo。 入力に一致する弦。

このような状況にどのように対処しますか? 答えは次のとおりです。ドット(。)文字をエスケープして、その特別な意味が無視されるようにする必要があります。

次のセクションでさらに詳しく見ていきましょう。

3. エスケープ文字

正規表現のJavaAPIドキュメントによると、特別な意味を持つ文字をエスケープする方法は2つあります。 言い換えれば、それらを通常の文字として扱われるように強制することです。

それらが何であるかを見てみましょう:

  1. メタ文字の前に円記号(\)を付けます
  2. メタ文字を\Qおよび\Eで囲みます

これは、前に見た例で、ドット文字をエスケープする場合は、ドット文字の前にバックスラッシュ文字を配置する必要があることを意味します。 または、ドット文字を\Qと\Eの間に配置することもできます。

3.1. バックスラッシュを使用したエスケープ

これは、正規表現のメタ文字をエスケープするために使用できる手法の1つです。 ただし、バックスラッシュ文字はJava Stringリテラルでもエスケープ文字であることがわかっています。 したがって、バックスラッシュ文字を使用して任意の文字(\文字自体を含む)の前に置く場合は、バックスラッシュ文字を2倍にする必要があります。

したがって、この例では、このテストに示すように正規表現を変更する必要があります。

@Test
public void givenRegexWithDotEsc_whenMatchingStr_thenNotMatching() {
    String strInput = "foof";
    String strRegex = "foo\\.";

    assertEquals(false, strInput.matches(strRegex));
}

ここでは、ドット文字がエスケープされているため、マッチャーはそれを単にドットとして扱い、ドットで終わるパターンを見つけようとします(つまり、 foo。)。

この場合、そのパターンの入力 String に一致するものがないため、falseを返します。

3.2. \ Q&\Eを使用したエスケープ

または、 \Qおよび\Eを使用して特殊文字をエスケープすることもできます。 \ Q は、 \ E までのすべての文字をエスケープする必要があることを示し、 \ E は、\で開始されたエスケープを終了する必要があることを示します。 Q

これは、 \Q\Eの間にあるものはすべてエスケープされることを意味します。

ここに示すテストでは、 Stringクラスのsplit()は、提供された正規表現を使用して照合を行います。

要件は、入力文字列をパイプ(|)文字で単語に分割することです。 したがって、正規表現パターンを使用してこれを行います。

パイプ文字は、正規表現でエスケープする必要があるメタ文字です。

ここで、エスケープは \Q\Eの間にパイプ文字を配置することによって行われます。

@Test
public void givenRegexWithPipeEscaped_whenSplitStr_thenSplits() {
    String strInput = "foo|bar|hello|world";
    String strRegex = "\\Q|\\E";
    
    assertEquals(4, strInput.split(strRegex).length);
}

4. Pattern.quote(String S)メソッド

java.util.regex.Pattern クラスのPattern.Quote(String S)メソッドは、指定された正規表現パターンStringをリテラルパターンString。に変換します。入力Stringのすべてのメタ文字が通常の文字として扱われることを意味します。

この方法を使用すると、使用するよりも便利な代替手段になります \ Q \ E 与えられたものを包むように彼らと一緒に。

このメソッドの動作を見てみましょう。

@Test
public void givenRegexWithPipeEscQuoteMeth_whenSplitStr_thenSplits() {
    String strInput = "foo|bar|hello|world";
    String strRegex = "|";

    assertEquals(4,strInput.split(Pattern.quote(strRegex)).length);
}

このクイックテストでは、 Pattern.quote()メソッドを使用して、指定された正規表現パターンをエスケープし、Stringリテラルに変換します。 言い換えれば、正規表現パターンに存在するすべてのメタ文字をエスケープします。 それはと同様の仕事をしています \ Q \ E

パイプ文字はPattern.quote()メソッドによってエスケープされ、 split()はそれをStringリテラルとして解釈して入力を分割します。

ご覧のとおり、これははるかにクリーンなアプローチであり、開発者はすべてのエスケープシーケンスを覚えておく必要はありません。

Pattern.quote は、ブロック全体を単一のエスケープシーケンスで囲んでいることに注意してください。 文字を個別にエスケープする場合は、トークン置換アルゴリズムを使用する必要があります。

5. その他の例

java .util.regex.MatcherreplaceAll()メソッドがどのように機能するかを見てみましょう。

特定の文字Stringのすべての出現箇所を別の文字に置き換える必要がある場合は、正規表現を渡すことでこのメソッドを使用できます。

$文字が複数回出現する入力があるとします。 取得したい結果は、$文字が£に置き換えられた同じ文字列です。

このテストは、パターン$がエスケープされずに渡される方法を示しています。

@Test
public void givenRegexWithDollar_whenReplacing_thenNotReplace() {
 
    String strInput = "I gave $50 to my brother."
      + "He bought candy for $35. Now he has $15 left.";
    String strRegex = "$";
    String strReplacement = "£";
    String output = "I gave £50 to my brother."
      + "He bought candy for £35. Now he has £15 left.";
    
    Pattern p = Pattern.compile(strRegex);
    Matcher m = p.matcher(strInput);
        
    assertThat(output, not(equalTo(m.replaceAll(strReplacement))));
}

このテストでは、$£に正しく置き換えられていないことが示されています。

ここで、正規表現パターンをエスケープすると、置換が正しく行われ、次のコードスニペットに示すようにテストに合格します。

@Test
public void givenRegexWithDollarEsc_whenReplacing_thenReplace() {
 
    String strInput = "I gave $50 to my brother."
      + "He bought candy for $35. Now he has $15 left.";
    String strRegex = "\\$";
    String strReplacement = "£";
    String output = "I gave £50 to my brother."
      + "He bought candy for £35. Now he has £15 left.";
    Pattern p = Pattern.compile(strRegex);
    Matcher m = p.matcher(strInput);
    
    assertEquals(output,m.replaceAll(strReplacement));
}

ここで\\$ に注意してください。これは、 $ 文字をエスケープし、パターンを正常に一致させることでトリックを実行します。

6. 結論

この記事では、Javaの正規表現でのエスケープ文字について説明しました。

正規表現をエスケープする必要がある理由と、それを実現するためのさまざまな方法について説明しました。

いつものように、この記事に関連するソースコードはGitHubにあります。