2012-01-26 27 views
5

Tôi đang cố gắng phân tích một số tài liệu.regex: chuỗi với các phần tùy chọn

Một docstrings ví dụ là:

Test if a column field is larger than a given value 
    This function can also be called as an operator using the '>' syntax 

    Arguments: 
     - DbColumn self 
     - string or float value: the value to compare to 
      in case of string: lexicographic comparison 
      in case of float: numeric comparison 
    Returns: 
     DbWhere object 

Cả ArgumentsReturns phần là không bắt buộc. Tôi muốn regex của tôi trở lại như nhóm mô tả (dòng đầu tiên), phần Arguments (nếu có) và phần Returns (nếu có).

Các regex tôi có bây giờ là:

m = re.search('(.*)(Arguments:.*)(Returns:.*)', s, re.DOTALL) 

và các công trình trong trường hợp tất cả ba phần có mặt nhưng không càng sớm càng Arguments hoặc Returns phần không có sẵn. Tôi đã thử một số biến thể với các công cụ sửa đổi không tham lam như ?? nhưng không có kết quả.

Edit: Khi ArgumentsReturns phần có mặt, tôi thực sự sẽ chỉ muốn để phù hợp với văn bản sau khi Arguments:Returns: tương ứng.

Cảm ơn!

+1

Đơn đặt hàng luôn được cố định? I. e., Là 'Đối số' luôn sau văn bản chuẩn và trước' Trả về'? –

+0

Có, đơn đặt hàng luôn được sửa. – BioGeek

Trả lời

7

Hãy thử với:

re.search('^(.*?)(Arguments:.*?)?(Returns:.*)?$', s, re.DOTALL) 

Chỉ cần làm cho nhóm thứ hai và thứ ba tùy chọn bằng cách thêm một ?, và làm cho vòng loại của hai nhóm đầu tiên không tham lam bằng (một lần nữa) phụ thêm một ? trên chúng (có, khó hiểu).

Ngoài ra, nếu bạn sử dụng công cụ sửa đổi không tham lam vào nhóm đầu tiên của mẫu, nó sẽ khớp với chuỗi con ngắn nhất có thể, trong đó cho .* là chuỗi trống. Bạn có thể khắc phục điều này bằng cách thêm ký tự cuối dòng ($) vào cuối mẫu, buộc nhóm đầu tiên khớp với ít ký tự nhất có thể để thỏa mãn mẫu, tức là toàn bộ chuỗi khi không có Arguments và không Returns phần và mọi thứ trước các phần đó, khi có mặt.

Edit: OK, nếu bạn chỉ muốn chụp các văn bản sau các Arguments:Returns: thẻ, bạn sẽ phải gài trong một nhóm vài chi tiết. Chúng tôi sẽ không sử dụng tất cả các nhóm, vì vậy đặt tên cho chúng -với các <?P<name> ký hiệu (một dấu câu hỏi, argh!) - đang bắt đầu có ý nghĩa:

>>> m = re.search('^(?P<description>.*?)(Arguments:(?P<arguments>.*?))?(Returns:(?P<returns>.*))?$', s, re.DOTALL) 
>>> m.groupdict()['description'] 
"Test if a column field is larger than a given value\n This function can also be called as an operator using the '>' syntax\n\n " 
>>> m.groupdict()['arguments'] 
'\n  - DbColumn self\n  - string or float value: the value to compare to\n   in case of string: lexicographic comparison\n   in case of float: numeric comparison\n ' 
>>> m.groupdict()['returns'] 
'\n  DbWhere object' 
>>> 
+0

Hoạt động như một sự quyến rũ! Làm thế nào bạn sẽ sửa đổi regex nếu, cho các phần tùy chọn, tôi chỉ muốn phù hợp với văn bản sau khi 'Arguments' và' Returns'? – BioGeek

+0

Một cái gì đó như 're.search ('^ (. *?) (Đối số: (. *?))? (Trả về: (. *))? $', Doc, re.DOTALL)' hoạt động, nhưng tôi không ' t chăm sóc cho nhóm thứ hai và thứ tư nó trả về. – BioGeek

+0

Tôi đã chỉnh sửa câu trả lời của mình. Chỉ cần đặt tên cho các nhóm và quên đi 'groups()', sử dụng 'groupdict()' để thay thế. – Chewie

3

Nếu bạn muốn để phù hợp với văn bản sau khi tùy chọn Arguments:Returns: phần, bạn không muốn sử dụng (?P<name>...) để đặt tên cho nhóm chụp, bạn cũng có thể sử dụng, (?:...), phiên bản không bắt buộc của dấu ngoặc đơn thông thường.

Các regex sẽ trông như thế này:

m = re.search('^(.*?)(?:Arguments:(.*?))?(?:Returns:(.*?))?$', doc, re.DOTALL) 
#      ^^     ^^ 

Theo Python3 documentation:

(?:...)

Một phiên bản không chụp ngoặc thường xuyên. Phù hợp với bất kỳ cụm từ thông dụng nào bên trong dấu ngoặc đơn, nhưng chuỗi con phù hợp với nhóm không thể được truy lục sau khi thực hiện khớp hoặc được tham chiếu sau trong mẫu.

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