Java正規表現APIの手引き

Java Regular Expressions APIガイド

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, MatcherPatternSyntaxException:の3つのクラスで構成されています。

  • Patternオブジェクトはコンパイルされた正規表現です。 Patternクラスはパブリックコンストラクターを提供しません。 パターンを作成するには、最初にそのパブリック静的compileメソッドの1つを呼び出す必要があります。これにより、Patternオブジェクトが返されます。 これらのメソッドは、最初の引数として正規表現を受け入れます。

  • Matcherオブジェクトはパターンを解釈し、入力Stringに対して一致操作を実行します。 また、パブリックコンストラクターも定義しません。 Patternオブジェクトでmatcherメソッドを呼び出すことにより、Matcherオブジェクトを取得します。

  • PatternSyntaxExceptionオブジェクトは、正規表現パターンの構文エラーを示す未チェックの例外です。

これらのクラスを詳細に検討します。ただし、Javaで正規表現がどのように構築されるかを最初に理解する必要があります。

異なる環境の正規表現にすでに精通している場合、特定の違いを見つけることができますが、それらは最小限です。

4. 簡単な例

Let’s start with the simplest use case for a regex.前述のように、正規表現が文字列に適用されると、0回以上一致する場合があります。

java.util.regex APIでサポートされているパターンマッチングの最も基本的な形式はmatch of a String literalです。 たとえば、正規表現がfooで、入力Stringfooの場合、Stringsは同一であるため、一致は成功します。

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

    assertTrue(matcher.find());
}

まず、静的なcompileメソッドを呼び出して、使用するパターンを渡すことにより、Patternオブジェクトを作成します。

次に、Matcherオブジェクトを作成し、Patternオブジェクトの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;
}

一致するものがない場合、テストは失敗し、そうでない場合は合格します。

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を見つけた後、残りは任意の文字として表示されます。 そのため、一致するのは1つだけです。

APIは、この記事でさらに詳しく調べる他のいくつかのメタ文字<([\{\^-=$!|]})?*+.>をサポートします。

6. キャラクタークラス

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

6.1. またはクラス

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

上記のテストでは、ユニオンセットが3、4、および5をスキップするため、9個の整数のうち6個のみが一致します。

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のStringがあるにもかかわらず、上記の例で3つの一致が得られる理由を説明しています。 3番目の一致は、長さがゼロの空のStringです。

テキストのゼロまたは無制限の時間に一致させるには、量指定子*を使用します。

@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回を超えないオカレンスを指定したため、代わりに1回の一致が得られ、一致することができない単一のaaaaが単独で表示されます。

ただし、APIを使用すると、マッチャーが範囲の下限から開始できるように、怠惰なアプローチまたは消極的なアプローチを指定できます。この場合、2つのオカレンスをaaおよびaaとしてマッチングします。

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

    assertEquals(matches, 2);
}

9. グループのキャプチャ

APIでは、treat multiple characters as a single unit through capturing groupsも可能です。

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

このセクションでは、Java regex 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は境界マッチングもサポートしています。 入力テキストのどこで正確に一致するかを気にする場合、これが私たちが探しているものです。 前の例では、一致が見つかったかどうかだけを気にかけました。

テキストの先頭で必要な正規表現が真である場合にのみ一致させるために、キャレット^.を使用する。

テキスト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);
}

テキストの最後で要求された正規表現が真である場合にのみ一致させるために、ドル文字$. Aマッチは次のような場合に見付けられる。

@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正規表現を使用します。

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

@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の先頭、および1つのテキストと別のテキストの間のスペースが単語の境界を示すために合格しますが、次のテストは反対のことを示しています。

@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メソッドの別のバリアントがあります。

これらのフラグは、単に抽象化された整数値です。 テストクラスのrunTestメソッドをオーバーロードして、3番目の引数としてフラグを取得できるようにします。

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には、そのコンポーネント文字eu0065、およびアキュートアクセントu0301用の個別のコードポイントもあります。 この場合、複合文字u`00E9は、2文字シーケンスu0065` u`0301.`と区別できません。

デフォルトでは、マッチングでは標準的な等価性は考慮されません。

@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では、#を使用して正規表現にコメントを含めることができます。 これは、他のプログラマーにはすぐには分からないかもしれない複雑な正規表現の文書化に役立ちます。

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

@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に対してアサートすることに関心があるため、前の一致を返すmatchergroupメソッドを使用します。

最初に、デフォルトの動作を確認します。

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

Pattern.LITERAL

このモードでは、マッチャーはメタ文字、エスケープ文字、または正規表現構文に特別な意味を与えません。 このフラグがないと、マッチャーは次の正規表現を入力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

デフォルトでは、^$のメタ文字は、入力String全体の最初と最後でそれぞれ完全に一致します。 マッチャーは、行末記号を無視します。

@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クラスのいくつかの便利なメソッドを見ていきます。 わかりやすくするために、機能別にグループ化します。

12.1. インデックスメソッド

インデックスメソッドは、入力Stringのどこで一致が見つかったかを正確に示す有用なインデックス値を提供します。 次のテストでは、入力Stringdogの一致の開始インデックスと終了インデックスを確認します。

@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. 交換方法

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

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パッケージの最も重要な機能についても説明しました。

ここで使用されているすべてのコードサンプルを含むプロジェクトの完全なソースコードは、GitHub projectにあります。