web-dev-qa-db-ja.com

Java正規表現キャプチャーグループ

このコードブロックを理解しようとしています。最初のもので、私たちが表現で探しているのは何ですか?

私の理解するところでは、それは任意の文字(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");
        }
    }

}
150
Xivilai

あなたが抱えている問題は数量詞の種類にあります。最初のグループで greedy 数量詞を使用しています(index 1 - index 0はPattern全体を表します)。可能な限り一致します(また、any文字なので、順序どおりにの文字数に一致します。次のグループの条件を満たすために)。

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

第3グループに従って、それは最後のディジットの後で何でも一致します。

最初のグループでそれを消極的な数量詞に変更すると、期待通りの結果が得られます。つまり、3000です。part.

1番目のグループの疑問符に注意してください。

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では、名前付きグループを使用できるため、はるかに簡単です。

215
Mena

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

  1. 最初のグループ(m.group(0))は常にあなたの正規表現でカバーされる領域全体を捉えます。この場合、それは文字列全体です。
  2. 正規表現はデフォルトで欲張りです。つまり、最初のグループは正規表現に違反することなく可能な限り多くの部分をキャプチャします。 (.*)(\\d+)(正規表現の最初の部分)は最初のグループの...QT300 intと2番目のグループの0をカバーします。
  3. 最初のグループを欲張らないようにすることでこれを素早く修正できます:(.*)(.*?)に変更してください。

貪欲対怠惰の詳細については、このサイトをチェックしてください

14
f1sh

ドキュメントから:

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は行全体を送信します。

4

あなたの理解は正しいです。しかし、私たちが通り抜けるならば:

  • (.*)は文字列全体を飲み込みます。
  • (\\d+)が満足されるように文字を返す必要があります(これが03000ではなく捉えられる理由です)。
  • 最後の(.*)は残りを捉えます。

しかし、その作者の本来の意図が何であったのかよくわかりません。

3
fge