Grup Pengambilan Java Regex

170

Saya mencoba memahami blok kode ini. Yang pertama, apa yang kita cari dalam ekspresi?

Pemahaman saya adalah bahwa itu karakter apa saja (0 atau lebih kali *) diikuti oleh angka antara 0 dan 9 (satu atau lebih kali +) diikuti oleh karakter apa saja (0 atau lebih kali *).

Ketika ini dijalankan hasilnya adalah:

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

Bisakah seseorang tolong melalui ini dengan saya?

Apa keuntungan menggunakan kelompok Menangkap?

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

}
Xivilai
sumber
1
Untuk menyisipkan baris baru, tempatkan 2 spasi di akhir baris. Lebih lanjut tentang sintaks markdown: en.wikipedia.org/wiki/Markdown - Lihat juga: stackoverflow.com/editing-help
assylias

Jawaban:

248

Masalah yang Anda hadapi adalah dengan tipe quantifier. Anda menggunakan quantifier rakus di grup pertama Anda (indeks 1 - indeks 0 mewakili keseluruhan Pattern), yang berarti akan cocok sebanyak mungkin (dan karena itu karakter apa pun , itu akan cocok dengan karakter sebanyak yang ada untuk memenuhi kondisi untuk kelompok selanjutnya).

Singkatnya, grup pertama Anda .*cocok dengan apa saja selama grup berikutnya \\d+dapat mencocokkan sesuatu (dalam hal ini, digit terakhir).

Sesuai grup ke-3, itu akan cocok dengan apa pun setelah digit terakhir.

Jika Anda mengubahnya ke kuantifier enggan di grup 1 Anda, Anda akan mendapatkan hasil yang saya kira Anda harapkan, yaitu, bagian 3000 .

Catat tanda tanya di grup 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));
}

Keluaran:

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

Info lebih lanjut tentang Java di Pattern sini .

Akhirnya, grup penangkap dibatasi oleh kurung bundar, dan menyediakan cara yang sangat berguna untuk menggunakan referensi-balik (di antara hal-hal lain), setelah Anda Patterndicocokkan dengan input.

Di Java 6 grup hanya dapat direferensikan oleh pesanan mereka (waspadalah terhadap kelompok yang bersarang dan kehalusan memesan).

Di Java 7 itu jauh lebih mudah, karena Anda dapat menggunakan grup bernama.

Mena
sumber
Terima kasih! Apakah alasan grup 2 disimpan 0 karena seluruh baris dikonsumsi oleh quantifier serakah yang kemudian mundur hingga bersentuhan dengan satu atau lebih angka. 0 memuaskan ini sehingga ungkapan berhasil. Saya menemukan kelompok ketiga membingungkan, apakah quantifier rakus itu juga mengkonsumsi seluruh baris, tetapi mundur sampai menemukan satu atau lebih angka (\\ d +) yang seharusnya mendahuluinya?
Xivilai
@Xivilai izinkan saya menyempurnakan penjelasan saya dalam jawaban saya, hanya sebentar.
Mena
Itu penjelasan yang bagus. Jadi enggan mulai dari kiri dan hanya mengambil minimum sedangkan dengan serakah, itu akan mengambil sebanyak mungkin (mulai dari kanan), hanya berhenti sebelum digit terakhir untuk memenuhi kondisi itu. Kelompok ketiga mengambil sisanya.
Xivilai
@Xivilai kurang lebih. Itu selalu dimulai dari kiri dalam kasus ini. Berikut ini beberapa info lebih lanjut tentang quantifiers.
Mena
2
Anda dapat menggunakan grup tangkapan bernama di Java 5/6 dengan named-regexp.
16

Ini sepenuhnya oke.

  1. Grup pertama ( m.group(0)) selalu menangkap seluruh area yang dicakup oleh ekspresi reguler Anda . Dalam hal ini, seluruh string.
  2. Ekspresi reguler serakah secara default, artinya grup pertama menangkap sebanyak mungkin tanpa melanggar regex. (.*)(\\d+)( Bagian pertama regex Anda) mencakup ...QT300int grup pertama dan 0yang kedua.
  3. Anda dapat dengan cepat memperbaikinya dengan membuat grup pertama tidak tamak: ubah (.*)ke (.*?).

Untuk info lebih lanjut tentang rakus vs malas, lihat situs ini.

f1sh
sumber
4

Dari dokumen:

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().

Jadi, tangkap grup 0 kirim seluruh baris.

Michael Laffargue
sumber
3

Pemahaman Anda benar. Namun, jika kita berjalan melalui:

  • (.*) akan menelan seluruh string;
  • perlu mengembalikan karakter sehingga (\\d+)satistif (yang mengapa 0ditangkap, dan bukan 3000);
  • yang terakhir (.*)akan menangkap sisanya.

Namun, saya tidak yakin apa maksud asli si penulis.

Fge
sumber