Java Regexキャプチャグループ


170

このコードブロックを理解しようとしています。最初の1つは、式で何を探しているのですか?

私の理解では、任意の文字(0回以上*)の後に0から9までの任意の数字(1回以上+)が続き、その後に任意の文字(0回以上*)が続くことです。

これを実行すると、結果は次のようになります。

Found value: This order was placed for QT3000! OK?
Found value: This order was placed for QT300
Found value: 0

誰かが私と一緒にこれを経験してもらえますか?

キャプチャグループを使用する利点は何ですか?

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegexTut3 {

    public static void main(String args[]) {
        String line = "This order was placed for QT3000! OK?"; 
        String pattern = "(.*)(\\d+)(.*)";

        // Create a Pattern object
        Pattern r = Pattern.compile(pattern);

        // Now create matcher object.
        Matcher m = r.matcher(line);

        if (m.find()) {
            System.out.println("Found value: " + m.group(0));
            System.out.println("Found value: " + m.group(1));
            System.out.println("Found value: " + m.group(2));
        } else {
            System.out.println("NO MATCH");
        }
    }

}

1
新しい行を挿入するには、行の終わりに2つのスペースを置きます。
マークダウン

回答:


248

あなたが抱えている問題は、数量詞のタイプです。あなたは、使用している貪欲あなたの最初のグループ(インデックスに数量詞を1 -インデックス0は全体を表しPattern、それができるよう、それは限り一致しますどの手段、(それはだから)任意の文字、それが一致するだろう多くの文字として存在しているとして次のグループの条件を満たすため)。

つまり、.*次のグループ\\d+が何か(この場合は最後の数字)に一致できる限り、最初のグループは何にでも一致します。

3番目のグループと同様に、最後の桁以降のすべてに一致します。

これを最初のグループの消極的な量指定子に変更すると、期待どおりの結果、つまり3000の部分が得られます。

最初のグループの疑問符に注意してください。

String line = "This order was placed for QT3000! OK?";
Pattern pattern = Pattern.compile("(.*?)(\\d+)(.*)");
Matcher matcher = pattern.matcher(line);
while (matcher.find()) {
    System.out.println("group 1: " + matcher.group(1));
    System.out.println("group 2: " + matcher.group(2));
    System.out.println("group 3: " + matcher.group(3));
}

出力:

group 1: This order was placed for QT
group 2: 3000
group 3: ! OK?

Javaの詳細については、Pattern こちらをご覧ください

最後に、キャプチャグループは角かっこで区切られPatternており、入力と一致すると、(特に)後方参照を使用する非常に便利な方法を提供します。

Java 6では、グループは順序によってのみ参照できます(ネストされたグループと順序の微妙さに注意してください)。

Java 7では、名前付きグループを使用できるため、はるかに簡単です。


ありがとう!行全体が貪欲な量指定子によって消費されたため、グループ2が0を格納した理由です。貪欲な量指定子は、1つ以上の数値と接触するまでバックオフしました。0はこれを満たしたため、式は成功しました。3番目のグループは混乱します。貪欲な量指定子も行全体を消費しますが、その前にあるはずの1つ以上の数値(\\ d +)が見つかるまで後退しますか?
Xivilai 2013

@Xivilaiを使用すると、私の回答で説明を微調整できます。
Mena

それは良い説明です。したがって、嫌悪感は左から始まり、最小値を取るだけですが、貪欲では、(右から始めて)できるだけ多くかかり、最後の桁の前で停止してその条件を満たすだけです。3番目のグループが残りを行います。
Xivilai 2013

@Xivilai多かれ少なかれ。ただし、この場合は常に左から始まります。ここで数量についてのいくつかの詳細情報です。
Mena 2013

2
でJava 5/6の名前付きキャプチャグループを使用できますnamed-regexp

16

これはまったく問題ありません。

  1. 最初のグループ(m.group(0))は常に、正規表現でカバーされる領域全体をキャプチャします。この場合、それは文字列全体です。
  2. 正規表現はデフォルトで貪欲です。つまり、最初のグループは、正規表現に違反せずに可能な限り多くをキャプチャします。(.*)(\\d+)(あなたの正規表現の最初の部分)をカバーする...QT300int型に最初のグループをし、0第二に。
  3. 最初のグループを貪欲でないようにすることで、これをすばやく修正できます:に変更(.*)(.*?)ます。

貪欲と怠惰の詳細については、このサイトを確認してください


4

ドキュメントから:

Capturing groups</a> are indexed from left
 * to right, starting at one.  Group zero denotes the entire pattern, so
 * the expression m.group(0) is equivalent to m.group().

したがって、キャプチャグループ0は回線全体を送信します。


3

あなたの理解は正しいです。ただし、ウォークスルーした場合:

  • (.*) 文字列全体を飲み込みます。
  • (\\d+)満足するように文字を返す必要があります(そのため、0はキャプチャされ、はキャプチャされません3000)。
  • 最後(.*)は残りをキャプチャします。

しかし、著者の本来の意図が何であったかはわかりません。

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