1概要

この記事では、Java Regex APIと、Javaプログラミング言語で正規表現を使用する方法について説明します。

正規表現の世界では、grep、Perl、Python、PHP、awkなど、さまざまなフレーバーから選択できます。

つまり、あるプログラミング言語で機能する正規表現は、他の言語では機能しない可能性があります。 Javaの正規表現の構文は、Perlのものと最もよく似ています。


2セットアップ

Javaで正規表現を使用するために、特別な設定は必要ありません。

JDKには、正規表現操作専用の特別なパッケージ

java.util.regex

が含まれています。コードにインポートするだけです。

さらに、

java.lang.String

クラスには、コードでよく使用される正規表現のサポートも組み込まれています。


3 Java正規表現パッケージ


java.util.regex

パッケージは、

Pattern、Matcher

、および

PatternSyntaxException

の3つのクラスで構成されています。


  • Pattern

    オブジェクトはコンパイル済みの正規表現です。

    Pattern

    クラスはnoを提供します。

パブリックコンストラクターパターンを作成するには、まずパブリック静的

compile

メソッドの1つを呼び出す必要があります。このメソッドは次に

Pattern

オブジェクトを返します。これらのメソッドは最初の引数として正規表現を受け入れます。


  • Matcher

    オブジェクトはパターンを解釈し、一致操作を実行します

入力

String

に対して。また、パブリックコンストラクタも定義されていません。

Pattern

オブジェクトの

matcher

メソッドを呼び出すことによって、

Matcher

オブジェクトを取得します。


  • PatternSyntaxException

    オブジェクトは未チェックの例外です。

正規表現パターンの構文エラーを示します。

これらのクラスについて詳しく説明します。ただし、最初に正規表現がJavaでどのように構成されているかを理解する必要があります。

あなたがすでに別の環境からの正規表現に精通しているならば、あなたはある違いを見つけるかもしれませんが、それらは最小限です。


4簡単な例

  • 正規表現の最も単純な使用例から始めましょう** 前述のように、正規表現が文字列に適用されると、0回以上一致する可能性があります。


java.util.regex

APIによってサポートされるパターンマッチングの最も基本的な形式は、

String

リテラル



マッチングです。たとえば、正規表現が

foo

で入力

String



foo

の場合、

Strings

は同一であるため、一致は成功します。

@Test
public void givenText__whenSimpleRegexMatches__thenCorrect() {
    Pattern pattern = Pattern.compile("foo");
    Matcher matcher = pattern.matcher("foo");

    assertTrue(matcher.find());
}

まず、静的な

compile

メソッドを呼び出して、使用したいパターンを渡して

Pattern

オブジェクトを作成します。

次に、

Pattern

オブジェクトの

matcher

メソッドを呼び出して、一致を確認するテキストを渡して

Matcher

オブジェクトを作成します。

その後、Matcherオブジェクトのメソッド

find

を呼び出します。


find

メソッドは入力テキストを進めていき、一致するたびにtrueを返すので、一致カウントを見つけるためにも使用できます。

@Test
public void givenText__whenSimpleRegexMatchesTwice__thenCorrect() {
    Pattern pattern = Pattern.compile("foo");
    Matcher matcher = pattern.matcher("foofoo");
    int matches = 0;
    while (matcher.find()) {
        matches++;
    }

    assertEquals(matches, 2);
}

さらにテストを実行するので、

runTest

というメソッドで一致数を見つけるためのロジックを抽象化できます。

public static int runTest(String regex, String text) {
    Pattern pattern = Pattern.compile(regex);
    Matcher matcher = pattern.matcher(text);
    int matches = 0;
    while (matcher.find()) {
        matches++;
    }
    return matches;
}

0回マッチしたらテストは失敗し、そうでなければ合格です。


5メタキャラクター

メタ文字は、検索パターンにロジックを追加するという意味で、パターンのマッチング方法に影響します。 Java APIはいくつかのメタ文字をサポートしています。最もわかりやすいのは、任意の文字に一致するドット

“。”

です。

@Test
public void givenText__whenMatchesWithDotMetach__thenCorrect() {
    int matches = runTest(".", "foo");

    assertTrue(matches > 0);
}

正規表現

foo

がテキスト

foo



foofoo

を2回マッチさせた前の例を考えてみましょう。正規表現でドットメタ文字を使用した場合、2番目のケースでは2つの一致は得られません。

@Test
public void givenRepeatedText__whenMatchesOnceWithDotMetach__thenCorrect() {
    int matches= runTest("foo.", "foofoo");

    assertEquals(matches, 1);
}

正規表現の

foo

の後のドットに注意してください。最後のドット部分はそれ以降の文字を意味するので、マッチャーは

foo

が先行するすべてのテキストにマッチします。したがって、最初の

foo

を見つけた後、残りは任意の文字と見なされます。だからこそ、一試合しかないのです。

APIは他のいくつかのメタ文字

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

をサポートしています。


6. キャラクタークラス

公式の


パターン


クラス仕様を参照すると、サポートされている正規表現構造の概要がわかります。文字クラスの下には、約6つの構成体があります。


6.1. ORクラス


[abc]

として構築されました。セット内の任意の要素が一致します。

@Test
public void givenORSet__whenMatchesAny__thenCorrect() {
    int matches = runTest("[abc]", "b");

    assertEquals(matches, 1);
}

それらがすべてテキストに含まれている場合は、順番に関係なくそれぞれが個別に照合されます。

@Test
public void givenORSet__whenMatchesAnyAndAll__thenCorrect() {
    int matches = runTest("[abc]", "cab");

    assertEquals(matches, 3);
}

それらは

String

の一部として交代することもできます。次の例では、最初の文字をセットの各要素に置き換えて異なる単語を作成すると、それらはすべて一致します。

@Test
public void givenORSet__whenMatchesAllCombinations__thenCorrect() {
    int matches = runTest("[bcr]at", "bat cat rat");

    assertEquals(matches, 3);
}


6.2. NORクラス

上記のセットは、最初の要素としてキャレットを追加することによって無効になります。

@Test
public void givenNORSet__whenMatchesNon__thenCorrect() {
    int matches = runTest("[^abc]", "g");

    assertTrue(matches > 0);
}

他のケース:

@Test
public void givenNORSet__whenMatchesAllExceptElements__thenCorrect() {
    int matches = runTest("[^bcr]at", "sat mat eat");

    assertTrue(matches > 0);
}


6.3. レンジクラス

一致したテキストが収まる範囲をハイフン( – )を使用して指定するクラスを定義できます。同様に、範囲を無効にすることもできます。

大文字のマッチング

@Test
public void givenUpperCaseRange__whenMatchesUpperCase__
  thenCorrect() {
    int matches = runTest(
      "[A-Z]", "Two Uppercase alphabets 34 overall");

    assertEquals(matches, 2);
}

小文字のマッチング

@Test
public void givenLowerCaseRange__whenMatchesLowerCase__
  thenCorrect() {
    int matches = runTest(
      "[a-z]", "Two Uppercase alphabets 34 overall");

    assertEquals(matches, 26);
}

大文字と小文字の両方を一致させる:

@Test
public void givenBothLowerAndUpperCaseRange__
  whenMatchesAllLetters__thenCorrect() {
    int matches = runTest(
      "[a-zA-Z]", "Two Uppercase alphabets 34 overall");

    assertEquals(matches, 28);
}

与えられた範囲の数字にマッチする:

@Test
public void givenNumberRange__whenMatchesAccurately__
  thenCorrect() {
    int matches = runTest(
      "[1-5]", "Two Uppercase alphabets 34 overall");

    assertEquals(matches, 2);
}

他の範囲の数とのマッチング

@Test
public void givenNumberRange__whenMatchesAccurately__
  thenCorrect2(){
    int matches = runTest(
      "[30-35]", "Two Uppercase alphabets 34 overall");

    assertEquals(matches, 1);
}

* 6.4。ユニオンクラス**

共用文字クラスは、2つ以上の文字クラスを組み合わせた結果です。

@Test
public void givenTwoSets__whenMatchesUnion__thenCorrect() {
    int matches = runTest("[1-3[7-9]]", "123456789");

    assertEquals(matches, 6);
}

上記のテストでは、9個の整数のうち6個に一致します。これは、和集合が3、4、5をスキップするためです。


6.5. 交差点クラス

共用体クラスと同様に、このクラスは2つ以上のセットの間で共通の要素を選択することから得られます。交差を適用するには、__を使います。

@Test
public void givenTwoSets__whenMatchesIntersection__thenCorrect() {
    int matches = runTest("[1-6&&[3-9]]", "123456789");

    assertEquals(matches, 4);
}

2つの集合の交差には4つの要素しかないので、4つの一致が得られます。


6.6. 減算クラス

減算を使用して、1つ以上の文字クラスを否定することができます。たとえば、奇数の10進数のセットと一致させるとします。

@Test
public void givenSetWithSubtraction__whenMatchesAccurately__thenCorrect() {
    int matches = runTest("[0-9&&[^2468]]", "123456789");

    assertEquals(matches, 5);
}


1,3,5,7,9

のみが一致します。


7. 定義済みの文字クラス

Java正規表現APIは定義済みの文字クラスも受け入れます。上記の文字クラスの中には、コードを直感的にわかりにくくするものの、短い形式で表現できるものがあります。この正規表現のJavaバージョンの特別な特徴の1つは、エスケープ文字です。

これから説明するように、ほとんどの文字はバックスラッシュで始まります。これはJavaでは特別な意味を持ちます。これらを

Pattern

クラスでコンパイルするには、先頭のバックスラッシュをエスケープする必要があります。つまり、

\ d



\\ d

になります。

一致する数字、

[0-9]

と同等

@Test
public void givenDigits__whenMatches__thenCorrect() {
    int matches = runTest("\\d", "123");

    assertEquals(matches, 3);
}


[^ 0-9]

と同等の、数字以外の文字との一致:

@Test
public void givenNonDigits__whenMatches__thenCorrect() {
    int mathces = runTest("\\D", "a6c");

    assertEquals(matches, 2);
}

一致する空白

@Test
public void givenWhiteSpace__whenMatches__thenCorrect() {
    int matches = runTest("\\s", "a c");

    assertEquals(matches, 1);
}

非空白スペースのマッチング

@Test
public void givenNonWhiteSpace__whenMatches__thenCorrect() {
    int matches = runTest("\\S", "a c");

    assertEquals(matches, 2);
}


[a-zA-Z

0-9]__と同等の単語文字と一致

@Test
public void givenWordCharacter__whenMatches__thenCorrect() {
    int matches = runTest("\\w", "hi!");

    assertEquals(matches, 2);
}

非単語文字のマッチング

@Test
public void givenNonWordCharacter__whenMatches__thenCorrect() {
    int matches = runTest("\\W", "hi!");

    assertEquals(matches, 1);
}


8数量詞

Java正規表現APIでは、量指定子を使用することもできます。これらにより、一致する出現回数を指定して、一致の動作をさらに調整することができます。

テキストを0回または1回一致させるには、



数量詞を使用します。

@Test
public void givenZeroOrOneQuantifier__whenMatches__thenCorrect() {
    int matches = runTest("\\a?", "hi");

    assertEquals(matches, 3);
}

あるいは、Java正規表現APIによってもサポートされている中括弧構文を使用することができます。

@Test
public void givenZeroOrOneQuantifier__whenMatches__thenCorrect2() {
    int matches = runTest("\\a{0,1}", "hi");

    assertEquals(matches, 3);
}

この例では、長さゼロの一致の概念を紹介します。そのため、数量詞の一致しきい値がゼロの場合、すべての入力の最後に空の

String

を含むテキスト内のすべてのものと常に一致します。つまり、入力が空の場合でも、長さゼロの一致が1回返されます。

これは、長さ2のS

__tring


があるにもかかわらず、上記の例で3つの一致がある理由を説明しています。 3番目の一致は、長さ0の空の

String__です。

テキストを0回または無限回一致させるには、** 数量詞を使用します。

@Test
public void givenZeroOrManyQuantifier__whenMatches__thenCorrect() {
     int matches = runTest("\\a** ", "hi");

     assertEquals(matches, 3);
}

支えられた代わり:

@Test
public void givenZeroOrManyQuantifier__whenMatches__thenCorrect2() {
    int matches = runTest("\\a{0,}", "hi");

    assertEquals(matches, 3);
}

差がある数量詞は+で、マッチングしきい値は1です。

必要な

String

がまったく発生しない場合、長さゼロの

String

でなくても、一致はありません。

@Test
public void givenOneOrManyQuantifier__whenMatches__thenCorrect() {
    int matches = runTest("\\a+", "hi");

    assertFalse(matches);
}

支えられた代わり:

@Test
public void givenOneOrManyQuantifier__whenMatches__thenCorrect2() {
    int matches = runTest("\\a{1,}", "hi");

    assertFalse(matches);
}

Perlや他の言語のように、中括弧の構文は与えられたテキストを何度も照合するために使うことができます。

@Test
public void givenBraceQuantifier__whenMatches__thenCorrect() {
    int matches = runTest("a{3}", "aaaaaa");

    assertEquals(matches, 2);
}

上記の例では、

a

が連続して3回出現した場合にのみ一致が発生するため、2回一致します。しかし、次のテストでは、テキストが連続して2回しか表示されないため、一致は得られません。

@Test
public void givenBraceQuantifier__whenFailsToMatch__thenCorrect() {
    int matches = runTest("a{3}", "aa");

    assertFalse(matches > 0);
}

中括弧で範囲を使用すると、範囲の上限から一致するように一致が貪欲になります。

@Test
public void givenBraceQuantifierWithRange__whenMatches__thenCorrect() {
    int matches = runTest("a{2,3}", "aaaa");

    assertEquals(matches, 1);
}

少なくとも2つの出現回数を指定しましたが、3つを超えないようにしました。そのため、一致することができない単一の

aaa



a

だけがマッチャーに表示される場合、単一の一致を取得します。

ただし、APIを使用すると、マッチャーが範囲内の下限から開始できるように、遅延または消極的なアプローチを指定できます。この場合、

aa



aa

の2つの出現に一致します。

@Test
public void givenBraceQuantifierWithRange__whenMatchesLazily__thenCorrect() {
    int matches = runTest("a{2,3}?", "aaaa");

    assertEquals(matches, 2);
}


9グループをキャプチャする

このAPIを使えば、

グループをキャプチャして

複数の文字を1つの単位として扱うこともできます。

キャプチャしているグループに番号を添付し、これらの番号を使用して逆参照を許可します。

このセクションでは、Java正規表現APIでキャプチャグループを使用する方法の例をいくつか紹介します。

入力テキストに2つの数字が隣り合っている場合にのみ一致するキャプチャグループを使用しましょう。

@Test
public void givenCapturingGroup__whenMatches__thenCorrect() {
    int maches = runTest("(\\d\\d)", "12");

    assertEquals(matches, 1);
}

上記の一致に付けられた番号は

1

です。これは、後方参照を使用して、テキストの一致部分の別の出現箇所と一致させたいことを照合者に伝えるためです。この方法ではなく、

@Test
public void givenCapturingGroup__whenMatches__thenCorrect2() {
    int matches = runTest("(\\d\\d)", "1212");

    assertEquals(matches, 2);
}

入力に対して2つの別々の一致がある場合、1つの一致を持つことができますが、逆参照を使用して入力の全長に渡って同じ正規表現の一致を伝搬することができます。

@Test
public void givenCapturingGroup__whenMatchesWithBackReference__
  thenCorrect() {
    int matches = runTest("(\\d\\d)\\1", "1212");

    assertEquals(matches, 1);
}

同じ結果を得るために、後方参照なしで正規表現を繰り返さなければならない場合は、次のようになります。

@Test
public void givenCapturingGroup__whenMatches__thenCorrect3() {
    int matches = runTest("(\\d\\d)(\\d\\d)", "1212");

    assertEquals(matches, 1);
}

同様に、他の繰り返し数に対しても、後方参照はマッチャーに入力を単一の一致として見せることができます。

@Test
public void givenCapturingGroup__whenMatchesWithBackReference__
  thenCorrect2() {
    int matches = runTest("(\\d\\d)\\1\\1\\1", "12121212");

    assertEquals(matches, 1);
}

しかし、最後の桁まで変更しても、一致は失敗します。

@Test
public void givenCapturingGroupAndWrongInput__
  whenMatchFailsWithBackReference__thenCorrect() {
    int matches = runTest("(\\d\\d)\\1", "1213");

    assertFalse(matches > 0);
}

エスケープのバックスラッシュを忘れないようにすることが重要です。これはJava構文では非常に重要です。


10境界マッチャー

Java正規表現APIは境界マッチングもサポートします。入力テキストの正確に一致する場所を気にする場合は、これが私たちが探しているものです。前の例では、私たちが気にしたのは、一致が見つかったかどうかだけでした。

必要な正規表現がテキストの冒頭でtrueの場合にのみマッチするように、キャレット

^ .

を使います

テキスト

dog

が最初にあるため、このテストは失敗します。

@Test
public void givenText__whenMatchesAtBeginning__thenCorrect() {
    int matches = runTest("^dog", "dogs are friendly");

    assertTrue(matches > 0);
}

次のテストは失敗します。

@Test
public void givenTextAndWrongInput__whenMatchFailsAtBeginning__
  thenCorrect() {
    int matches = runTest("^dog", "are dogs are friendly?");

    assertFalse(matches > 0);
}

テキストの最後で必須の正規表現が真である場合にのみマッチするために、ドル記号

$ .

を使います。

@Test
public void givenText__whenMatchesAtEnd__thenCorrect() {
    int matches = runTest("dog$", "Man's best friend is a dog");

    assertTrue(matches > 0);
}

そしてここで一致は見つかりません。

@Test
public void givenTextAndWrongInput__whenMatchFailsAtEnd__thenCorrect() {
    int matches = runTest("dog$", "is a dog man's best friend?");

    assertFalse(matches > 0);
}

必要なテキストが単語の境界で見つかった場合にのみ一致させたい場合は、正規表現の最初と最後に

\\ b

regexを使用します。

スペースは単語の境界です:

@Test
public void givenText__whenMatchesAtWordBoundary__thenCorrect() {
    int matches = runTest("\\bdog\\b", "a dog is friendly");

    assertTrue(matches > 0);
}

行頭の空の文字列も単語の境界です。

@Test
public void givenText__whenMatchesAtWordBoundary__thenCorrect2() {
    int matches = runTest("\\bdog\\b", "dog is man's best friend");

    assertTrue(matches > 0);
}

これらのテストは、

String

の始まり、およびあるテキストと別のテキストとの間のスペースが単語の境界を示しているために成功しますが、次のテストはその逆を示しています。

@Test
public void givenWrongText__whenMatchFailsAtWordBoundary__thenCorrect() {
    int matches = runTest("\\bdog\\b", "snoop dogg is a rapper");

    assertFalse(matches > 0);
}

行に現れる2単語の文字は単語の境界を示しませんが、正規表現の末尾を変更して単語以外の境界を探すことでパスを通過させることができます。

@Test
public void givenText__whenMatchesAtWordAndNonBoundary__thenCorrect() {
    int matches = runTest("\\bdog\\B", "snoop dogg is a rapper");
    assertTrue(matches > 0);
}


11パターンクラスメソッド

以前は、基本的な方法で

Pattern

オブジェクトを作成しました。

ただし、このクラスには

compile

メソッドの別のバリエーションがあり、パターンの一致方法に影響を与えるregex引数と一緒に一連のフラグを受け入れます。

これらのフラグは単に抽象化された整数値です。 3番目の引数としてフラグを取ることができるように、テストクラスの

runTest

メソッドをオーバーロードしましょう。

public static int runTest(String regex, String text, int flags) {
    pattern = Pattern.compile(regex, flags);
    matcher = pattern.matcher(text);
    int matches = 0;
    while (matcher.find()){
        matches++;
    }
    return matches;
}

このセクションでは、サポートされているさまざまなフラグとその使用方法について説明します。


  • Pattern.CANON

    EQ__ **

このフラグは正準等価を有効にします。指定した場合、2つの文字は、それらの完全な正規分解が一致する場合に限り、一致すると見なされます。

アクセント付きのUnicode文字

é

を考えます。その複合コードポイントは

u00E9

です。ただし、Unicodeには、その構成要素文字

e



u0065

、およびアクセント記号

u0301

用のコードポイントもあります。この場合、複合文字

u00E9

は、2文字のシーケンス

u0065 u0301

と区別がつきません。

デフォルトでは、マッチングは正規の等価性を考慮に入れません。

@Test
public void givenRegexWithoutCanonEq__whenMatchFailsOnEquivalentUnicode__thenCorrect() {
    int matches = runTest("\u00E9", "\u0065\u0301");

    assertFalse(matches > 0);
}

しかし、フラグを追加すると、テストは成功します。

@Test
public void givenRegexWithCanonEq__whenMatchesOnEquivalentUnicode__thenCorrect() {
    int matches = runTest("\u00E9", "\u0065\u0301", Pattern.CANON__EQ);

    assertTrue(matches > 0);
}



Pattern.CASE


INSENSITIVE __

このフラグは大文字と小文字を区別せずにマッチングを有効にします。デフォルトでは、大文字と小文字の区別が考慮されます。

@Test
public void givenRegexWithDefaultMatcher__whenMatchFailsOnDifferentCases__thenCorrect() {
    int matches = runTest("dog", "This is a Dog");

    assertFalse(matches > 0);
}

したがって、このフラグを使用して、デフォルトの動作を変更できます。

@Test
public void givenRegexWithCaseInsensitiveMatcher
  __whenMatchesOnDifferentCases__thenCorrect() {
    int matches = runTest(
      "dog", "This is a Dog", Pattern.CASE__INSENSITIVE);

    assertTrue(matches > 0);
}

同じ結果を得るために、同等の埋め込みフラグ式を使用することもできます。

@Test
public void givenRegexWithEmbeddedCaseInsensitiveMatcher
  __whenMatchesOnDifferentCases__thenCorrect() {
    int matches = runTest("(?i)dog", "This is a Dog");

    assertTrue(matches > 0);
}



Pattern.COMMENTS

Java APIでは、#を使って正規表現にコメントを含めることができます。これは複雑な正規表現を文書化するのを助けることができます。

commentsフラグはマッチャーに正規表現内の空白やコメントを無視させ、パターンのみを考慮させる。デフォルトのマッチングモードでは、次のテストは失敗します。

@Test
public void givenRegexWithComments__whenMatchFailsWithoutFlag__thenCorrect() {
    int matches = runTest(
      "dog$  #check for word dog at end of text", "This is a dog");

    assertFalse(matches > 0);
}

これは、マッチャーがスペースと#文字を含む入力テキスト内の正規表現全体を探すためです。しかし、このフラグを使用すると、余分なスペースは無視され、#で始まるすべてのテキストは各行で無視されるコメントと見なされます。

@Test
public void givenRegexWithComments__whenMatchesWithFlag__thenCorrect() {
    int matches = runTest(
      "dog$  #check end of text","This is a dog", Pattern.COMMENTS);

    assertTrue(matches > 0);
}

これに対する代替の埋め込みフラグ式もあります。

@Test
public void givenRegexWithComments__whenMatchesWithEmbeddedFlag__thenCorrect() {
    int matches = runTest(
      "(?x)dog$  #check end of text", "This is a dog");

    assertTrue(matches > 0);
}



Pattern.DOTALL

デフォルトでは、正規表現でドット“。”式を使用すると、改行文字に遭遇するまで入力

String

内のすべての文字と一致します。

このフラグを使用すると、一致には行末記号も含まれます。次の例を見れば、もっとよく理解できるでしょう。これらの例は少し異なります。マッチした

String

に対してアサートすることに興味があるので、前回のマッチを返す

matcher

‘s s

group

メソッドを使います。

まず、デフォルトの動作がわかります。

@Test
public void givenRegexWithLineTerminator__whenMatchFails__thenCorrect() {
    Pattern pattern = Pattern.compile("(.** )");
    Matcher matcher = pattern.matcher(
      "this is a text" + System.getProperty("line.separator")
        + " continued on another line");
    matcher.find();

    assertEquals("this is a text", matcher.group(1));
}

ご覧のとおり、行末記号の前の入力の最初の部分だけが一致します。


dotall

モードでは、行末文字を含むテキスト全体が一致します。

@Test
public void givenRegexWithLineTerminator__whenMatchesWithDotall__thenCorrect() {
    Pattern pattern = Pattern.compile("(.** )", Pattern.DOTALL);
    Matcher matcher = pattern.matcher(
      "this is a text" + System.getProperty("line.separator")
        + " continued on another line");
    matcher.find();
    assertEquals(
      "this is a text" + System.getProperty("line.separator")
        + " continued on another line", matcher.group(1));
}


dotall

モードを有効にするために埋め込みのフラグ式を使うこともできます。

@Test
public void givenRegexWithLineTerminator__whenMatchesWithEmbeddedDotall
  __thenCorrect() {

    Pattern pattern = Pattern.compile("(?s)(.** )");
    Matcher matcher = pattern.matcher(
      "this is a text" + System.getProperty("line.separator")
        + " continued on another line");
    matcher.find();

    assertEquals(
      "this is a text" + System.getProperty("line.separator")
        + " continued on another line", matcher.group(1));
}



パターン。リテラル

このモードでは、matcherはメタ文字、エスケープ文字、または正規表現構文に特別な意味を与えません。このフラグがなければ、マッチャーは以下の正規表現を入力

String

と照合します。

@Test
public void givenRegex__whenMatchesWithoutLiteralFlag__thenCorrect() {
    int matches = runTest("(.** )", "text");

    assertTrue(matches > 0);
}

これは、すべての例で見てきたデフォルトの動作です。

しかしながら、このフラグでは、マッチャーはそれを解釈するのではなく

(。** )

を探しますのでマッチは見つかりません:

@Test
public void givenRegex__whenMatchFailsWithLiteralFlag__thenCorrect() {
    int matches = runTest("(.** )", "text", Pattern.LITERAL);

    assertFalse(matches > 0);
}

必要な文字列を追加すると、テストは成功します。

@Test
public void givenRegex__whenMatchesWithLiteralFlag__thenCorrect() {
    int matches = runTest("(.** )", "text(.** )", Pattern.LITERAL);

    assertTrue(matches > 0);
}

リテラル解析を有効にするための埋め込みフラグ文字はありません。



Pattern.MULTILINE

デフォルトでは、

^



$

メタ文字は、入力全体の先頭と末尾でそれぞれ完全に一致します。マッチャーは行末記号を無視します。

@Test
public void givenRegex__whenMatchFailsWithoutMultilineFlag__thenCorrect() {
    int matches = runTest(
      "dog$", "This is a dog" + System.getProperty("line.separator")
      + "this is a fox");

    assertFalse(matches > 0);
}

マッチャーは

String

全体の終わりで

dog

を検索しますが、

dog

はストリングの最初の行の終わりにあるため、マッチングは失敗します。

しかし、フラグを使用すると、マッチャーが行末記号を考慮に入れるので、同じテストに合格します。そのため、文字列

dog

は行が終了する直前に見つかるため、成功します。

@Test
public void givenRegex__whenMatchesWithMultilineFlag__thenCorrect() {
    int matches = runTest(
      "dog$", "This is a dog" + System.getProperty("line.separator")
      + "this is a fox", Pattern.MULTILINE);

    assertTrue(matches > 0);
}

これが埋め込みフラグバージョンです。

@Test
public void givenRegex__whenMatchesWithEmbeddedMultilineFlag__
  thenCorrect() {
    int matches = runTest(
      "(?m)dog$", "This is a dog" + System.getProperty("line.separator")
      + "this is a fox");

    assertTrue(matches > 0);
}


12. Matcherクラスのメソッド

このセクションでは、

Matcher

クラスの便利なメソッドをいくつか見ていきます。わかりやすくするために、機能ごとにグループ化します。

** 12.1. インデックス方法

インデックスメソッドは、入力

String

内で一致が見つかった場所を正確に示す有用なインデックス値を提供します。次のテストでは、入力

String

内の

dog

に対する一致の開始インデックスと終了インデックスを確認します。

@Test
public void givenMatch__whenGetsIndices__thenCorrect() {
    Pattern pattern = Pattern.compile("dog");
    Matcher matcher = pattern.matcher("This dog is mine");
    matcher.find();

    assertEquals(5, matcher.start());
    assertEquals(8, matcher.end());
}


12.2. 研究方法

スタディメソッドは入力

String

をたどり、パターンが見つかったかどうかを示すブール値を返します。一般的に使用されるのは、

matches

および

lookingAt

メソッドです。


matches

メソッドと

lookingAt

メソッドはどちらも入力シーケンスをパターンと突き合わせようとします。違いは、

matches

は入力シーケンス全体を一致させる必要があるのに対し、

lookingAt

は一致させないことです。

どちらの方法も入力

String

の先頭から始まります。

@Test
public void whenStudyMethodsWork__thenCorrect() {
    Pattern pattern = Pattern.compile("dog");
    Matcher matcher = pattern.matcher("dogs are friendly");

    assertTrue(matcher.lookingAt());
    assertFalse(matcher.matches());
}

matchesメソッドは、次のような場合にtrueを返します。

@Test
public void whenMatchesStudyMethodWorks__thenCorrect() {
    Pattern pattern = Pattern.compile("dog");
    Matcher matcher = pattern.matcher("dog");

    assertTrue(matcher.matches());
}


12.3. 交換方法

置換メソッドは、入力文字列内のテキストを置換するのに役立ちます。一般的なものは

replaceFirst



replaceAll

です。


replaceFirst

および

replaceAll

メソッドは、指定された正規表現に一致するテキストを置き換えます。名前が示すように、

replaceFirst

は最初の出現箇所を置き換え、

replaceAll

はすべての出現箇所を置き換えます。

@Test
public void whenReplaceFirstWorks__thenCorrect() {
    Pattern pattern = Pattern.compile("dog");
    Matcher matcher = pattern.matcher(
      "dogs are domestic animals, dogs are friendly");
    String newStr = matcher.replaceFirst("cat");

    assertEquals(
      "cats are domestic animals, dogs are friendly", newStr);
}

すべての出現箇所を置き換えます。

@Test
public void whenReplaceAllWorks__thenCorrect() {
    Pattern pattern = Pattern.compile("dog");
    Matcher matcher = pattern.matcher(
      "dogs are domestic animals, dogs are friendly");
    String newStr = matcher.replaceAll("cat");

    assertEquals("cats are domestic animals, cats are friendly", newStr);
}


13. 結論

この記事では、Javaで正規表現を使用する方法と、

java.util.regex

パッケージの最も重要な機能について説明しました。

ここで使用されているすべてのコードサンプルを含むプロジェクトの完全なソースコードはhttps://github.com/eugenp/tutorials/tree/master/core-java[GitHubプロジェクト]にあります。