'Lười biếng' và 'tham lam' có nghĩa là gì trong bối cảnh của các biểu thức thông thường?


Câu trả lời:


644

Tham lam sẽ tiêu thụ càng nhiều càng tốt. Từ http://www.THER-expressions.info/repeat.html chúng tôi thấy ví dụ về việc thử khớp các thẻ HTML với <.+>. Giả sử bạn có những điều sau đây:

<em>Hello World</em>

Bạn có thể nghĩ rằng <.+>( .có nghĩa là bất kỳ nhân vật không phải dòng mới nào+có nghĩa là một hoặc nhiều ) sẽ chỉ phù hợp với <em></em>, trong thực tế, nó sẽ rất tham lam, và đi từ đầu <đến cuối >. Điều này có nghĩa là nó sẽ phù hợp <em>Hello World</em>thay vì những gì bạn muốn.

Làm cho nó lười biếng ( <.+?>) sẽ ngăn chặn điều này. Bằng cách thêm vào ?sau +, chúng tôi bảo nó lặp lại ít nhất có thể , vì vậy lần đầu tiên >nó xuất hiện, là nơi chúng tôi muốn dừng kết hợp.

Tôi khuyến khích bạn tải xuống RegExr , một công cụ tuyệt vời sẽ giúp bạn khám phá Biểu thức chính quy - Tôi sử dụng nó mọi lúc.


2
Vì vậy, nếu bạn sử dụng tham lam, bạn sẽ có 3 (1 yếu tố + 2 thẻ) phù hợp hay chỉ 1 trận đấu (1 yếu tố)?
ajsie

10
Nó sẽ chỉ khớp 1 lần, bắt đầu từ lần đầu tiên < và kết thúc bằng lần cuối > .
Sampson

3
Nhưng làm cho nó lười biếng sẽ khớp hai lần, cho chúng ta cả thẻ mở và đóng, bỏ qua văn bản ở giữa (vì nó không phù hợp với biểu thức).
Sampson

Một công cụ tuyệt vời khác mà tôi luôn sử dụng: debuggex.com Nó cũng có chức năng "Nhúng vào StackOverflow".
Ron van der Heijden

8
Chỉ cần thêm rằng có một cách tham lam để đi về nó, quá: <[^>]+> regex101.com/r/lW0cY6/1
alanbuchanan

302

'Tham lam' có nghĩa là khớp chuỗi dài nhất có thể.

'Lazy' có nghĩa là khớp chuỗi ngắn nhất có thể.

Ví dụ, các h.+ltrận đấu tham lam 'hell'trong 'hello'nhưng h.+?ltrận đấu lười biếng 'hel'.


97
Rực rỡ, lười biếng sẽ dừng lại ngay khi điều kiện l được thỏa mãn, nhưng tham lam nghĩa là nó sẽ chỉ dừng lại một khi điều kiện l không được thỏa mãn nữa?
Andrew S

3
Đối với tất cả những người đọc bài đăng: các bộ định lượng tham lam hoặc lười biếng sẽ không phù hợp với chuỗi con dài nhất / ngắn nhất có thể. Bạn sẽ phải sử dụng mã thông báo tham lam nóng nảy hoặc sử dụng các phương pháp không phải là regex.
Wiktor Stribiż

3
@AndrewS Đừng nhầm lẫn bởi ví dụ kép. Nó khá lười biếng sẽ phù hợp với chuỗi con ngắn nhất có thể trong khi tham lam sẽ phù hợp với chuỗi dài nhất có thể. h.+lTrận đấu tham lam 'helol'trong 'helolo'nhưng h.+?ltrận đấu lười biếng 'hel'.
v.shashenko

3
@FloatingRock: Số x?có nghĩa xlà tùy chọn nhưng +?là một cú pháp khác nhau. Nó có nghĩa là ngừng tìm kiếm sau khi bạn tìm thấy một cái gì đó phù hợp - lười biếng phù hợp.
slebetman

1
@FloatingRock: Về cách bạn phân biệt cú pháp khác nhau, đơn giản: ?có nghĩa là tùy chọn và +?có nghĩa là lười biếng. Do đó, \+?phương tiện +là tùy chọn.
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  |
+-------------------+-----------------+------------------------------+

Thêm một? đến một bộ định lượng để làm cho nó vô duyên tức là lười biếng.

Ví dụ:
chuỗi kiểm tra: stackoverflow
greedy reg biểu thức : s.*ooutput: stackoverflo w
lazy reg biểu thức : s.*?ooutput: stacko verflow


2
không phải ?? tương đương với ? . Tương tự, không phải là {n}? tương đương với {n}
Số945

5
@BreakingBenjamin: không ?? không tương đương với ?, khi nó có lựa chọn trả về 0 hoặc 1 lần xuất hiện, nó sẽ chọn phương án 0 (lười biếng). Để thấy sự khác biệt, so sánh re.match('(f)?(.*)', 'food').groups()với re.match('(f)??(.*)', 'food').groups(). Về sau, (f)??sẽ không khớp với 'f' hàng đầu mặc dù có thể. Do đó, 'f' sẽ được khớp với nhóm chụp '. *' Thứ hai. Tôi chắc rằng bạn có thể tạo một ví dụ với '{n}?' quá. Phải thừa nhận rằng hai cái này rất hiếm khi được sử dụng.
smci

55

Tham lam có nghĩa là biểu hiện của bạn sẽ phù hợp với một nhóm càng lớn càng tốt, lười biếng có nghĩa là nó sẽ phù hợp với nhóm nhỏ nhất có thể. Đối với chuỗi này:

abcdefghijklmc

và biểu thức này:

a.*c

Một trận đấu tham lam sẽ phù hợp với toàn bộ chuỗi, và một trận đấu lười biếng sẽ chỉ khớp với lần đầu tiên abc.


16

Theo như tôi biết, hầu hết các công cụ regex đều tham lam theo mặc định. Thêm một dấu hỏi ở cuối bộ định lượng sẽ cho phép kết hợp lười biếng.

Như @Andre S đã đề cập trong bình luận.

  • Tham lam: Tiếp tục tìm kiếm cho đến khi điều kiện không được thỏa mãn.
  • Lười biếng: Ngừng tìm kiếm một khi điều kiện được thỏa mãn.

Tham khảo ví dụ dưới đây để biết những gì tham lam và những gì lười biếng.

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


Kết quả là:

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

Lấy từ www.THER-expressions.info

Tham lam: Các bộ lượng hóa tham lam trước tiên cố gắng lặp lại mã thông báo nhiều lần nhất có thể và dần dần từ bỏ các kết quả trùng khớp khi quay lại động cơ để tìm một kết quả khớp tổng thể.

Lười biếng : Đầu tiên, bộ định lượng lười biếng lặp lại mã thông báo vài lần theo yêu cầu và dần dần mở rộng trận đấu khi quay lại động cơ thông qua regex để tìm một kết quả khớp tổng thể.


6

Từ biểu thức chính quy

Các bộ lượng hóa tiêu chuẩn trong các biểu thức chính quy là tham lam, có nghĩa là chúng khớp với nhau nhiều nhất có thể, chỉ trả lại khi cần thiết để khớp với phần còn lại của biểu thức chính quy.

Bằng cách sử dụng bộ định lượng lười biếng, biểu thức sẽ thử kết quả khớp tối thiểu trước.


4

Tham lam kết hợp. Hành vi mặc định của các biểu thức thông thường là tham lam. Điều đó có nghĩa là nó cố gắng trích xuất càng nhiều càng tốt cho đến khi nó phù hợp với một mẫu ngay cả khi một phần nhỏ hơn đã đủ về mặt cú pháp.

Thí dụ:

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

Thay vì khớp cho đến lần xuất hiện đầu tiên của '>', nó đã trích xuất toàn bộ chuỗi. Đây là hành vi tham lam mặc định hoặc 'lấy tất cả' của regex.

Mặt khác , kết hợp lười biếng , 'mất càng ít càng tốt'. Điều này có thể được thực hiện bằng cách thêm một ?ở cuối mẫu.

Thí dụ:

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

Nếu bạn chỉ muốn lấy kết quả khớp đầu tiên, thay vào đó hãy sử dụng phương pháp tìm kiếm.

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

Nguồn: Ví dụ về Python Regex


3

Tham lam có nghĩa là nó sẽ tiêu thụ mô hình của bạn cho đến khi không còn ai trong số họ và nó không thể nhìn xa hơn.

Lười biếng sẽ dừng lại ngay khi nó gặp phải mẫu đầu tiên bạn yêu cầu.

Một ví dụ phổ biến mà tôi thường gặp là \s*-\s*?về regex([0-9]{2}\s*-\s*?[0-9]{7})

Đầu tiên \s*được phân loại là tham lam vì *và sẽ trông càng nhiều khoảng trắng càng tốt sau khi gặp các chữ số và sau đó tìm kiếm một ký tự gạch ngang "-". Trường hợp thứ hai \s*?là lười biếng vì hiện tại *?có nghĩa là nó sẽ trông nhân vật khoảng trắng đầu tiên và dừng lại ở đó.


3

Hiển thị tốt nhất bằng ví dụ. Chuỗi. 192.168.1.1và một regex tham lam \b.+\b Bạn có thể nghĩ rằng điều này sẽ cung cấp cho bạn octet đầu tiên nhưng thực sự phù hợp với toàn bộ chuỗi. Tại sao? Bởi vì. + Là tham lam và một trận đấu tham lam phù hợp với mọi nhân vật 192.168.1.1cho đến khi nó đến cuối chuỗi. Đây là bit quan trọng! Bây giờ, nó bắt đầu quay lại một ký tự một lần cho đến khi tìm thấy kết quả khớp với mã thông báo thứ 3 (\b ).

Nếu chuỗi tệp văn bản 4GB và 192.168.1.1 bắt đầu, bạn có thể dễ dàng thấy cách quay lại này sẽ gây ra sự cố.

Để tạo một regex không tham lam (lười biếng) hãy đặt dấu chấm hỏi sau khi tìm kiếm tham lam của bạn, vd

*?
??
+?

Điều xảy ra bây giờ là mã thông báo 2 (+? ) tìm thấy kết quả khớp, regex di chuyển dọc theo một ký tự và sau đó thử mã thông báo tiếp theo ( \b) thay vì mã thông báo 2 ( +?). Vì vậy, nó leo dọc theo gừng.


0

Công cụ định lượng tham lam giống như IRS / ATO: họ mất nhiều nhất có thể:

Nếu nó ở đó, họ sẽ đến và lấy nó. Họ sẽ lấy tất cả:

Ví dụ: IRS khớp với biểu thức chính quy này: .*

$50,000 - IRS sẽ lấy tất cả. Những kẻ tham lam.*{4}? ers

Xem ở đây để biết ví dụ: regexr.com/4t27f

Các bộ lượng hóa không tham lam - họ mất ít nhất có thể

Mặt khác, nếu tôi yêu cầu hoàn thuế, IRS đột nhiên trở nên không tham lam và họ sử dụng bộ định lượng này:

(.{2}?)([0-9]*)chống lại biểu hiện này: $50,000Nhóm đầu tiên không cần thiết và chỉ khớp $5- vì vậy tôi nhận được một$5 hoàn lại tiền. Phần còn lại được chú Sam lấy để tiêu xài hoang phí.

Xem ở đây: Ví dụ không tham lam .

Quan tâm làm gì?

Nó trở nên quan trọng nếu bạn đang cố gắng khớp các phần nhất định của biểu thức. Đôi khi bạn không muốn khớp mọi thứ.


-3

cố gắng hiểu hành vi sau:

    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); // ""
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.