2011-11-13 34 views
13

Tôi cần phải tìm tất cả các kết quả phù hợp trong một chuỗi cho một regex nhất định. Tôi đã sử dụng findall() để làm điều đó cho đến khi tôi bắt gặp một trường hợp mà nó không làm những gì tôi mong đợi. Ví dụ:python - regex tìm kiếm và findall

regex = re.compile('(\d+,?)+') 
s = 'There are 9,000,000 bicycles in Beijing.' 

print re.search(regex, s).group(0) 
> 9,000,000 

print re.findall(regex, s) 
> ['000'] 

Trong trường hợp này search() trả về những gì tôi cần (trận đấu dài nhất) nhưng findall() cư xử khác nhau, mặc dù các tài liệu có nghĩa nó phải giống nhau:

findall() trận đấu tất cả các lần xuất hiện của một hoa văn, không chỉ là hình mẫu đầu tiên là search().

  • Tại sao hành vi lại khác?

  • Làm cách nào để đạt được kết quả của search() với findall() (hoặc cái gì khác)?

+0

thử ''([\ d,] +)'' – dawg

Trả lời

15

Ok, tôi thấy những gì đang xảy ra ... từ các tài liệu:

Nếu một hoặc nhiều nhóm có mặt trong mô hình, trả về một danh sách của các nhóm; đây sẽ là danh sách các bộ dữ liệu nếu mẫu có nhiều nhóm.

Khi nó quay ra, bạn có một nhóm "(\ d + ,?)" ... như vậy, những gì nó có trở lại là sự xuất hiện cuối cùng của nhóm này, hoặc 000.

Một giải pháp là để bao quanh toàn bộ regex theo nhóm, như thế này,

regex = re.compile('((\d+,?)+)') 

sau đó, nó sẽ trả về [('9,000,000', '000')], là một bộ chứa cả hai nhóm phù hợp. tất nhiên, bạn chỉ quan tâm đến cái đầu tiên.

Cá nhân, tôi sẽ sử dụng regex

sau
regex = re.compile('((\d+,)*\d+)') 

để tránh phù hợp với những thứ như "đây là một số xấu 9123,"

Chỉnh sửa.

Dưới đây là một cách để tránh phải bao quanh biểu hiện bằng dấu ngoặc đơn hoặc đối phó với các bộ

s = "..." 
regex = re.compile('(\d+,?)+') 
it = re.finditer(regex, s) 

for match in it: 
    print match.group(0) 

finditer trả về một iterator mà bạn có thể sử dụng để truy cập vào tất cả các trận đấu được tìm thấy. các đối tượng kết hợp này giống nhau mà re.search trả về, do đó nhóm (0) trả về kết quả bạn mong đợi.

+0

Cảm ơn bạn đã giải thích. Hóa ra 'người tìm ra 'thực sự phù hợp hơn với những gì tôi đang làm như bạn đề nghị. Regex đến từ đầu vào của người dùng vì vậy tôi không có quyền kiểm soát nó. – armandino

7

@ aleph_null's answer giải thích chính xác nguyên nhân gây ra sự cố của bạn, nhưng tôi nghĩ tôi có giải pháp tốt hơn.Sử dụng regex này:

regex = re.compile(r'\d+(?:,\d+)*') 

Một số lý do tại sao nó tốt hơn:

  1. (?:...) là một tổ chức phi chụp, vì vậy bạn chỉ có được một kết quả cho mỗi trận đấu.

  2. \d+(?:,\d+)* là một regex tốt hơn, hiệu quả hơn và ít có khả năng trả về kết quả dương tính giả.

  3. Bạn nên luôn sử dụng chuỗi thô của Python cho các regex nếu có thể; bạn ít có khả năng bị ngạc nhiên bởi các chuỗi thoát regex (như \b cho ranh giới từ) được hiểu là chuỗi thoát chuỗi ký tự (như \b cho backspace).

+0

Cảm ơn Alan! Tôi đã đề cập trước đó nhưng tôi không có quyền kiểm soát regex vì nó là đầu vào của người dùng .. – armandino

+2

Không sao cả! Nhưng, đối với hồ sơ, cho phép người dùng nhập regexes được thực thi bởi ứng dụng của bạn là một ý tưởng tồi. Khi các quy trình viết sai (hoặc chỉ cần gõ nhanh) của chúng không khớp, hoặc làm hỏng hệ thống, chúng sẽ đổ lỗi * bạn * cho nó. ;) –

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