2013-05-16 30 views
16

Tôi chắc chắn rằng tôi đang thiếu một cái gì đó rõ ràng ở đây, nhưng tôi không thể làm cho R để sử dụng biểu thức thông thường không tham lam:chuỗi không tham lam biểu thức chính quy phù hợp với

> library(stringr) 
> str_match('xxx aaaab yyy', "a.*?b")           
    [,1] 
[1,] "aaaab" 

chức năng cơ sở xử theo cùng một cách:

> regexpr('a.*?b', 'xxx aaaab yyy') 
[1] 5 
attr(,"match.length") 
[1] 5 
attr(,"useBytes") 
[1] TRUE 

tôi mong chờ trận đấu là chỉ ab theo bình luận 'tham lam' trong http://stat.ethz.ch/R-manual/R-devel/library/base/html/regex.html:

Theo sự lặp lại mặc định là tham lam, vì vậy số lần lặp lại tối đa có thể được sử dụng. Điều này có thể được thay đổi thành 'tối thiểu' bằng cách thêm? để định lượng. (Có thêm định lượng cho phép đối sánh gần đúng: xem tài liệu TRE.)

Ai đó có thể giải thích cho tôi điều gì đang xảy ra?

Cập nhật. gì điên là trong một số trường hợp khác mô hình phi tham lam như mong đợi:

> str_match('xxx <a href="abc">link</a> yyy <h1>Header</h1>', '<a.*>') 
    [,1]           
[1,] "<a href=\"abc\">link</a> yyy <h1>Header</h1>" 
> str_match('xxx <a href="abc">link</a> yyy <h1>Header</h1>', '<a.*?>') 
    [,1]    
[1,] "<a href=\"abc\">" 

Trả lời

18

khái niệm khó khăn vì vậy tôi sẽ cố gắng hết sức mình ... Có người cảm thấy tự do để chỉnh sửa và giải thích tốt hơn nếu nó là một chút khó hiểu .

Biểu thức phù hợp với mẫu của bạn được tìm kiếm từ trái sang phải. Có, tất cả các chuỗi sau aaaab, aaab, aabab khớp với mẫu của bạn, nhưng aaaab là một trong số đó bắt đầu nhiều nhất ở bên trái là số được trả lại.

Vì vậy, ở đây, mẫu không tham lam của bạn không hữu ích lắm. Có lẽ ví dụ khác điều này sẽ giúp bạn hiểu rõ hơn khi một mô hình phi tham lam đá trong:

str_match('xxx aaaab yyy', "a.*?y") 
#  [,1]  
# [1,] "aaaab y" 

Ở đây tất cả các chuỗi aaaab y, aaaab yy, aaaab yyy phù hợp mô hình và bắt đầu tại vị trí tương đương, nhưng một trong những đầu tiên là trả về vì mô hình không tham lam.


Vì vậy, bạn có thể làm gì để bắt được số ab cuối cùng? Sử dụng điều này:

str_match('xxx aaaab yyy', ".*(a.*b)") 
#  [,1]  [,2] 
# [1,] "xxx aaaab" "ab" 

Làm thế nào nó hoạt động? Bằng cách thêm một mẫu tham lam .* ở mặt trước, bạn hiện đang buộc quá trình đặt a cuối cùng vào nhóm được chụp.

+0

Cảm ơn @floder - Tôi hoàn toàn quên rằng nó luôn bắt đầu khớp từ bên trái. Mọi người đang thảo luận trong một thời gian dài: http://www.nntp.perl.org/group/perl.perl6.language.regex/2000/12/msg507.html –

3

Vấn đề khớp với cửa sổ ngắn nhất giữa hai chuỗi. @flodel đề cập chính xác rằng một công cụ regex đang phân tích cú pháp chuỗi từ trái sang phải và do đó tất cả các kết quả phù hợp là ngoài cùng bên trái. Sự kiêu căng và lười biếng chỉ áp dụng cho các ranh giới bên phải: các số lượng tham lam nhận được các chất nền lên đến các ranh giới bên phải, và những người lười biếng sẽ phù hợp với sự xuất hiện đầu tiên của các mẫu con để theo dõi.

Xem ví dụ:

> library(stringr) 
> str_extract('xxx aaaab yyy', "a[^ab]*b") 
[1] "ab" 
> str_extract('xxx aaa xxx aaa zzz', "xxx.*?zzz") 
[1] "xxx aaa xxx aaa zzz" 
> str_extract('xxx aaa xxx aaa zzz', "xxx(?:(?!xxx|zzz).)*zzz") 
[1] "xxx aaa zzz" 

Việc đầu tiên và các kịch bản thứ ba trở lại cửa sổ ngắn nhất, điều thứ hai là một minh chứng của vấn đề hiện tại nhưng với một đầu vào multicharacter.

Kịch bản 1. Ranh giới là nhân vật duy nhất

Trong trường hợp ab là nhân vật duy nhất, cửa sổ ngắn nhất được tìm thấy bằng cách sử dụng một lớp nhân vật phủ nhận. a[^ab]*b sẽ dễ dàng lấy chuỗi con từ a cho đến b tiếp theo mà không cần a s và b s ở giữa.

Kịch bản 2. Ranh giới không phải là nhân vật đơn

Bạn có thể sử dụng một tempered greedy token trong những trường hợp này có thể được tiếp tục trải ra. Mẫu xxx(?:(?!xxx|zzz).)*zzz khớp với xxx, sau đó bất kỳ 0+ ký tự nào khác với ký tự dòng không phải là char khởi đầu của chuỗi xxx hoặc zzz char (số (?!xxx|zzz)lookahead tiêu cực không khớp nếu chuỗi con ngay lập tức khớp đúng mẫu lookahead), và sau đó là zzz.

Những phù hợp với kịch bản có thể dễ dàng sử dụng với cơ sở R regmatches (sử dụng một hương vị PCRE regex hỗ trợ lookaheads):

> x <- 'xxx aaa xxx aaa zzz xxx bbb xxx ccc zzz' 
> unlist(regmatches(x, gregexpr("xxx(?:(?!xxx|zzz).)*zzz", x, perl = TRUE))) 
[1] "xxx aaa zzz" "xxx ccc zzz" 

Một lưu ý: khi sử dụng một regex PCRE trong cơ sở R, hoặc ICU regex trong str_extract/str_match, . không khớp với các ký tự dòng, để bật hành vi đó, bạn cần phải thêm (?s) vào lúc bắt đầu mẫu (một công cụ sửa đổi DOTALL nội tuyến).

Các vấn đề liên quan