Sự khác biệt giữa. * Là gì? và. * biểu thức chính quy?


142

Tôi đang cố gắng tách một chuỗi thành hai phần bằng regex. Chuỗi được định dạng như sau:

text to extract<number>

Tôi đã sử dụng (.*?)<<(.*?)>hoạt động tốt nhưng sau khi đọc vào regex một chút, tôi mới bắt đầu tự hỏi tại sao tôi cần ?các biểu thức. Tôi chỉ thực hiện nó như thế sau khi tìm thấy chúng thông qua trang web này vì vậy tôi không chắc chắn chính xác sự khác biệt là gì.


Câu trả lời:


172

Đó là sự khác biệt giữa các đại lượng tham lam và không tham lam.

Xem xét đầu vào 101000000000100 .

Sử dụng 1.*1, *là tham lam - nó sẽ phù hợp cho đến cuối cùng, và sau đó quay lại cho đến khi nó có thể phù hợp 1, để lại cho bạn với 1010000000001.
.*?là không tham lam. *sẽ không có gì phù hợp, nhưng sau đó sẽ cố gắng khớp các ký tự phụ cho đến khi khớp 1, cuối cùng khớp101 .

Tất cả quantifiers có một chế độ không tham lam: .*?, .+?, .{2,6}?, và thậm chí.?? .

Trong trường hợp của bạn, một mẫu tương tự có thể là <([^>]*)>- khớp với bất cứ thứ gì ngoại trừ một dấu hiệu lớn hơn (nói đúng ra, nó khớp với 0 hoặc nhiều ký tự khác ngoài >giữa <>).

Xem Bảng định lượng Cheat .


Ah tuyệt vời tôi thích cái cuối cùng của bất cứ thứ gì ngoại trừ dấu>!
Doug

1
Bạn có thể giải thích hoặc chỉ ra một ví dụ về sự tham lam ?khác với người không tham lam ??như thế nào không?
AdrianHHH

4
Chắc chắn rồi. Đối với chuỗi "abc", regex /\w\w?\w/sẽ khớp với chuỗi đầy đủ "abc"- vì ?tham lam. /\w\w??\w/là lười biếng - nó sẽ chỉ phù hợp "ab". Nó sẽ chỉ quay lại và khớp "abc"nếu thất bại sau này.
Kobi

184

Tham lam vs không tham lam

Sự lặp lại trong regex theo mặc định là tham lam : họ cố gắng khớp càng nhiều đại diện càng tốt và khi điều này không hoạt động và họ phải quay lại, họ cố gắng khớp một lần ít hơn một lần, cho đến khi khớp với toàn bộ mô hình tìm. Kết quả là, khi một trận đấu cuối cùng xảy ra, một sự lặp lại tham lam sẽ khớp với càng nhiều đại diện càng tốt.

Bộ ?định lượng lặp lại thay đổi hành vi này thành không tham lam , còn được gọi là miễn cưỡng ( ví dụ Java ) (và đôi khi "lười biếng"). Ngược lại, sự lặp lại này trước tiên sẽ cố gắng khớp càng ít lần lặp lại càng tốt và khi điều này không hoạt động và họ phải quay lại, họ bắt đầu kết hợp thêm một lần nữa. Kết quả là, khi một trận đấu cuối cùng xảy ra, một sự lặp lại miễn cưỡng sẽ khớp với số ít đại diện càng tốt.

Người giới thiệu


Ví dụ 1: Từ A đến Z

Hãy so sánh hai mẫu này: A.*ZA.*?Z .

Cho đầu vào sau:

eeeAiiZuuuuAoooZeeee

Các mẫu mang lại kết quả khớp sau:

Trước tiên hãy tập trung vào những gì A.*Z. Khi nó phù hợp với cái đầu tiên A, sự .*tham lam, đầu tiên cố gắng khớp với càng nhiều .càng tốt.

eeeAiiZuuuuAoooZeeee
   \_______________/
    A.* matched, Z can't match

Zkhông khớp, nên quay lại động cơ và .*sau đó phải khớp với một ít hơn .:

eeeAiiZuuuuAoooZeeee
   \______________/
    A.* matched, Z still can't match

Điều này xảy ra một vài lần nữa, cho đến khi cuối cùng chúng ta đến với điều này:

eeeAiiZuuuuAoooZeeee
   \__________/
    A.* matched, Z can now match

Bây giờ Zcó thể khớp, vì vậy mô hình tổng thể khớp:

eeeAiiZuuuuAoooZeeee
   \___________/
    A.*Z matched

Ngược lại, sự lặp lại miễn cưỡng trong các A.*?Ztrận đấu đầu tiên càng ít .càng tốt, và sau đó lấy thêm .khi cần thiết. Điều này giải thích tại sao nó tìm thấy hai kết quả khớp trong đầu vào.

Đây là một đại diện trực quan về những gì hai mẫu phù hợp:

eeeAiiZuuuuAoooZeeee
   \__/r   \___/r      r = reluctant
    \____g____/        g = greedy

Ví dụ: Một thay thế

Trong nhiều ứng dụng, hai kết quả khớp trong đầu vào trên là những gì mong muốn, do đó, một sự miễn cưỡng .*?được sử dụng thay vì tham lam .*để ngăn chặn việc vượt qua. Tuy nhiên, đối với mẫu cụ thể này, có một cách thay thế tốt hơn, sử dụng lớp ký tự phủ định.

Mẫu A[^Z]*Zcũng tìm thấy hai kết quả khớp giống như A.*?Zmẫu cho đầu vào ở trên ( như đã thấy trên ideone.com ). [^Z]là những gì được gọi là một lớp nhân vật phủ định : nó phù hợp với bất cứ điều gì nhưng Z.

Sự khác biệt chính giữa hai mẫu là về hiệu năng: nghiêm ngặt hơn, lớp ký tự bị phủ định chỉ có thể khớp với một cách cho một đầu vào nhất định. Không thành vấn đề nếu bạn sử dụng công cụ sửa đổi tham lam hoặc miễn cưỡng cho mẫu này. Trong thực tế, trong một số hương vị, bạn thậm chí có thể làm tốt hơn và sử dụng cái được gọi là định lượng sở hữu, hoàn toàn không quay lại.

Người giới thiệu


Ví dụ 2: Từ A đến ZZ

Ví dụ này nên có tính minh họa: nó cho thấy các mẫu lớp nhân vật tham lam, miễn cưỡng và phủ định khớp với các đầu vào khác nhau như thế nào.

eeAiiZooAuuZZeeeZZfff

Đây là các kết quả khớp cho đầu vào trên:

Đây là một đại diện trực quan của những gì họ phù hợp:

         ___n
        /   \              n = negated character class
eeAiiZooAuuZZeeeZZfff      r = reluctant
  \_________/r   /         g = greedy
   \____________/g

Chủ đề liên quan

Đây là các liên kết đến câu hỏi và câu trả lời trên stackoverflow bao gồm một số chủ đề có thể được quan tâm.

Một sự lặp lại tham lam có thể vượt xa người khác


1
Ý tôi là nói rubular.com, không phải ideone.com. Đối với những người khác: đừng sửa lại bài đăng này cho tôi, tôi sẽ tự làm nó trong lần sửa đổi tiếp theo, cùng với các ví dụ khác. Hãy đưa ra phản hồi, đề xuất, vv trong các bình luận để tôi có thể kết hợp những ý kiến ​​đó.
đa gen


4
Câu trả lời này đã được thêm vào Câu hỏi thường gặp về Biểu hiện thường xuyên của Stack Overflow , trong phần "Định lượng> Thêm về sự khác biệt ..."
aliteralmind

Câu trả lời này thực sự xứng đáng là câu trả lời được chọn!. Cảm ơn bạn rất nhiều vì lời giải thích chi tiết của bạn.
masky007

Tôi thêm thẻ không tham lam . Tại sao, bởi vì câu hỏi cần nó, nhưng cũng bởi vì nó sẽ đưa nhiều người dùng đến câu trả lời tuyệt vời này. Nói cách khác, nếu bạn đưa ra một câu trả lời tuyệt vời và câu trả lời sử dụng một thẻ không có trong câu hỏi, sau đó thêm thẻ vì OP không biết rằng thẻ đó là mặc khải.
Guy Coder

20

Hãy nói rằng bạn có:

<a></a>

<(.*)>sẽ phù hợp với a></anơi như <(.*?)>sẽ phù hợp a. Cái sau dừng lại sau trận đấu đầu tiên của >. Nó kiểm tra một hoặc 0 trận đấu .*theo sau bởi biểu thức tiếp theo.

Biểu thức đầu tiên <(.*)>không dừng lại khi khớp với biểu thức đầu tiên >. Nó sẽ tiếp tục cho đến trận đấu cuối cùng của >.


Điều này dễ hiểu hơn lời giải thích ở trên.
Prometheus
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.