Apa arti 'malas' dan 'serakah' dalam konteks ekspresi reguler?


Jawaban:


644

Serakah akan mengkonsumsi sebanyak mungkin. Dari http://www.regular-expressions.info/repeat.html kita melihat contoh mencoba mencocokkan tag HTML dengan <.+>. Misalkan Anda memiliki yang berikut:

<em>Hello World</em>

Anda mungkin berpikir bahwa <.+>( .berarti karakter bukan baris baru dan +berarti satu atau lebih ) hanya akan cocok dengan <em>dan </em>, ketika pada kenyataannya itu akan sangat serakah, dan pergi dari yang pertama <ke yang terakhir >. Ini berarti itu akan cocok dengan <em>Hello World</em>yang Anda inginkan.

Membuatnya malas ( <.+?>) akan mencegah hal ini. Dengan menambahkan ?setelah +, kami katakan untuk mengulangi sesering mungkin , jadi yang pertama kali ditemukan >, adalah tempat kami ingin menghentikan pencocokan.

Saya mendorong Anda untuk mengunduh RegExr , alat hebat yang akan membantu Anda menjelajahi Ekspresi Reguler - Saya menggunakannya sepanjang waktu.


2
jadi jika Anda menggunakan serakah apakah Anda memiliki 3 (1 elemen + 2 tag) yang cocok atau hanya 1 yang cocok (1 elemen)?
ajsie

10
Hanya akan cocok 1 kali, mulai dari yang pertama < dan berakhir dengan yang terakhir > .
Sampson

3
Tetapi membuatnya malas akan cocok dua kali, memberi kami tag pembuka dan penutup, mengabaikan teks di antaranya (karena tidak sesuai dengan ekspresi).
Sampson

Alat hebat lain yang selalu saya gunakan: debuggex.com Ini juga memiliki fungsi "Embed on StackOverflow".
Ron van der Heijden

8
Hanya untuk menambahkan bahwa ada cara serakah untuk melakukannya, juga: <[^>]+> regex101.com/r/lW0cY6/1
alanbuchanan

302

'Serakah' berarti cocok dengan string terpanjang yang mungkin.

'Malas' berarti cocok dengan string yang sesingkat mungkin.

Sebagai contoh, serakah h.+lpertandingan 'hell'di 'hello'tetapi malas h.+?lpertandingan 'hel'.


97
Cemerlang, jadi malas akan berhenti begitu kondisi l puas, tapi serakah berarti hanya akan berhenti begitu kondisi l tidak puas lagi?
Andrew S

3
Untuk semua orang yang membaca pos: quantifier serakah atau malas sendiri tidak akan cocok dengan substring terpanjang / sesingkat mungkin. Anda harus menggunakan token serakah yang marah , atau menggunakan pendekatan non-regex.
Wiktor Stribiżew

3
@AndrewS Jangan bingung dengan ll ganda dalam contoh. Agak malas akan cocok dengan substring sesingkat mungkin sementara serakah akan cocok dengan yang terpanjang mungkin. h.+lPertandingan serakah 'helol'di 'helolo'tapi h.+?lpertandingan malas 'hel'.
v.shashenko

3
@ FloatingRock: No. x?berarti xadalah opsional tetapi +?sintaks yang berbeda. Itu berarti berhenti merawat setelah Anda menemukan sesuatu yang cocok - pencocokan malas.
slebetman

1
@ FloatingRock: Adapun bagaimana Anda membedakan sintaks yang berbeda, sederhana: ?berarti opsional dan +?berarti malas. Karena itu \+?berarti +adalah opsional.
slebetman

113
+-------------------+-----------------+------------------------------+
| Greedy quantifier | Lazy quantifier |        Description           |
+-------------------+-----------------+------------------------------+
| *                 | *?              | Star Quantifier: 0 or more   |
| +                 | +?              | Plus Quantifier: 1 or more   |
| ?                 | ??              | Optional Quantifier: 0 or 1  |
| {n}               | {n}?            | Quantifier: exactly n        |
| {n,}              | {n,}?           | Quantifier: n or more        |
| {n,m}             | {n,m}?          | Quantifier: between n and m  |
+-------------------+-----------------+------------------------------+

Tambah sebuah ? ke quantifier untuk membuatnya tidak berkelas yaitu malas.

Contoh:
string uji: stackoverflow
serakah ekspresi reg : s.*oOutput: stackoverflo w
ekspresi reg malas : s.*?oOutput: stacko verflow


2
tidak ?? setara dengan ? . Demikian pula, bukankah {n}? setara dengan {n}
Number945

5
@BreakingBenjamin: tidak ?? tidak setara dengan?, ketika ia memiliki pilihan untuk mengembalikan 0 atau 1 kejadian, ia akan memilih alternatif 0 (malas). Untuk melihat perbedaannya, bandingkan re.match('(f)?(.*)', 'food').groups()dengan re.match('(f)??(.*)', 'food').groups(). Dalam yang terakhir, (f)??tidak akan cocok dengan 'f' terkemuka meskipun itu bisa. Oleh karena itu, 'f' akan dicocokkan dengan kelompok tangkapan kedua '. *'. Saya yakin Anda dapat membuat contoh dengan '{n}?' terlalu. Harus diakui keduanya sangat jarang digunakan.
smci

55

Serakah berarti ekspresi Anda akan cocok dengan kelompok sebanyak mungkin, malas berarti cocok dengan kelompok sekecil mungkin. Untuk string ini:

abcdefghijklmc

dan ungkapan ini:

a.*c

Pertandingan serakah akan cocok dengan seluruh string, dan pertandingan malas akan cocok dengan yang pertama abc.


16

Sejauh yang saya tahu, kebanyakan mesin regex serakah secara default. Menambahkan tanda tanya di akhir kuantifier akan memungkinkan kecocokan malas.

Seperti @Andre S disebutkan dalam komentar.

  • Serakah: Terus mencari sampai kondisi tidak terpenuhi.
  • Malas: Berhenti mencari setelah kondisinya puas.

Lihat contoh di bawah ini untuk apa yang serakah dan apa yang malas.

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

public class Test {
    public static void main(String args[]){
        String money = "100000000999";
        String greedyRegex = "100(0*)";
        Pattern pattern = Pattern.compile(greedyRegex);
        Matcher matcher = pattern.matcher(money);
        while(matcher.find()){
            System.out.println("I'm greeedy and I want " + matcher.group() + " dollars. This is the most I can get.");
        }

        String lazyRegex = "100(0*?)";
        pattern = Pattern.compile(lazyRegex);
        matcher = pattern.matcher(money);
        while(matcher.find()){
            System.out.println("I'm too lazy to get so much money, only " + matcher.group() + " dollars is enough for me");
        }
    }
}


Hasilnya adalah:

I'm greeedy and I want 100000000 dollars. This is the most I can get.

I'm too lazy to get so much money, only 100 dollars is enough for me

9

Diambil Dari www.regular-expressions.info

Keserakahan : Kuantitatif serakah pertama kali mencoba mengulangi token sebanyak mungkin, dan secara bertahap menyerah pertandingan sebagai backtracks mesin untuk menemukan kecocokan keseluruhan.

Kemalasan : Pengukur malas pertama-tama mengulangi token sebanyak yang diperlukan, dan secara bertahap memperluas kecocokan saat engine mundur ke belakang melalui regex untuk menemukan kecocokan secara keseluruhan.


6

Dari ekspresi Reguler

Pengukur standar dalam ekspresi reguler adalah serakah, artinya mereka cocok sebanyak mungkin, hanya memberikan kembali seperlunya untuk mencocokkan sisa regex.

Dengan menggunakan kuantifier malas, ekspresi mencoba kecocokan minimal terlebih dahulu.


4

Pencocokan serakah. Perilaku default ekspresi reguler adalah menjadi serakah. Itu berarti ia mencoba untuk mengekstrak sebanyak mungkin sampai sesuai dengan suatu pola bahkan ketika bagian yang lebih kecil sudah cukup secara sintaksis.

Contoh:

import re
text = "<body>Regex Greedy Matching Example </body>"
re.findall('<.*>', text)
#> ['<body>Regex Greedy Matching Example </body>']

Alih-alih mencocokkan hingga kemunculan pertama '>', ia mengekstraksi seluruh string. Ini adalah perilaku regex default yang serakah atau 'ambil semuanya.

Pencocokan malas , di sisi lain, 'mengambil sesedikit mungkin'. Ini dapat dilakukan dengan menambahkan a ?di akhir pola.

Contoh:

re.findall('<.*?>', text)
#> ['<body>', '</body>']

Jika Anda hanya ingin pencocokan pertama yang diambil, gunakan metode pencarian sebagai gantinya.

re.search('<.*?>', text).group()
#> '<body>'

Sumber: Contoh Python Regex


3

Serakah berarti akan memakan pola Anda sampai tidak ada satupun yang tersisa dan tidak terlihat lagi.

Malas akan berhenti segera setelah akan menemukan pola pertama yang Anda minta.

Salah satu contoh umum yang sering saya temui adalah \s*-\s*?dari regex([0-9]{2}\s*-\s*?[0-9]{7})

Yang pertama \s*diklasifikasikan sebagai serakah karena *dan akan terlihat sebanyak mungkin ruang putih setelah digit dijumpai dan kemudian mencari karakter tanda hubung "-". Sedangkan yang kedua \s*?adalah malas karena masa kini *?yang berarti akan terlihat karakter ruang putih pertama dan berhenti di sana.


3

Terbaik ditunjukkan dengan contoh. Tali. 192.168.1.1dan regex serakah \b.+\b Anda mungkin berpikir ini akan memberi Anda oktet 1 tetapi sebenarnya cocok dengan seluruh string. Mengapa? Karena. + Rakus dan serakah cocok dengan setiap karakter 192.168.1.1hingga mencapai akhir string. Ini bagian yang penting! Sekarang mulai mundur satu karakter pada satu waktu hingga menemukan kecocokan untuk token ke-3 ( \b).

Jika string file teks 4GB dan 192.168.1.1 sudah di awal Anda bisa dengan mudah melihat bagaimana pengulangan ini akan menyebabkan masalah.

Untuk membuat regex yang tidak serakah (malas) beri tanda tanya setelah pencarian serakah Anda misalnya

*?
??
+?

Apa yang terjadi sekarang adalah token 2 ( +?) menemukan kecocokan, regex bergerak di sepanjang karakter dan kemudian mencoba token berikutnya ( \b) daripada token 2 ( +?). Jadi itu merayap dengan hati-hati.


0

Pengukur Serakah seperti IRS / ATO: mereka mengambil sebanyak yang mereka bisa:

Jika ada di sana, mereka akan datang dan mengambilnya. Mereka akan mengambil semuanya:

Misalnya, IRS cocok dengan regex ini: .*

$50,000 - IRS akan mengambil semuanya. Mereka serakah .*{4}?ers

Lihat di sini untuk contoh: regexr.com/4t27f

Penjumlah non-serakah - mereka mengambil sesedikit mungkin

Di sisi lain, jika saya meminta pengembalian pajak, IRS tiba-tiba menjadi tidak serakah, dan mereka menggunakan penghitung ini:

(.{2}?)([0-9]*)terhadap ungkapan ini: $50,000Grup pertama tidak membutuhkan dan hanya cocok $5- jadi saya mendapatkan $5pengembalian uang. Sisanya diambil oleh paman Sam untuk dihabiskan dengan sia-sia.

Lihat di sini: Contoh yang tidak tamak .

Kenapa mengganggu?

Menjadi penting jika Anda mencoba mencocokkan bagian-bagian tertentu dari ekspresi. Terkadang Anda tidak ingin mencocokkan segalanya.


-3

cobalah untuk memahami perilaku berikut:

    var input = "0014.2";

Regex r1 = new Regex("\\d+.{0,1}\\d+");
Regex r2 = new Regex("\\d*.{0,1}\\d*");

Console.WriteLine(r1.Match(input).Value); // "0014.2"
Console.WriteLine(r2.Match(input).Value); // "0014.2"

input = " 0014.2";

Console.WriteLine(r1.Match(input).Value); // "0014.2"
Console.WriteLine(r2.Match(input).Value); // " 0014"

input = "  0014.2";

Console.WriteLine(r1.Match(input).Value); // "0014.2"
Console.WriteLine(r2.Match(input).Value); // ""
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.