re.findall ('(ab | cd)', chuỗi) so với re.findall ('(ab | cd) +', chuỗi)


18

Trong một biểu thức chính quy của Python, tôi gặp phải vấn đề đơn lẻ này. Bạn có thể đưa ra hướng dẫn về sự khác biệt giữa re.findall('(ab|cd)', string)re.findall('(ab|cd)+', string)?

import re

string = 'abcdla'
result = re.findall('(ab|cd)', string)
result2 = re.findall('(ab|cd)+', string)
print(result)
print(result2)

Đầu ra thực tế là:

['ab', 'cd']
['cd']

Tôi bối rối không biết tại sao kết quả thứ hai cũng không chứa 'ab'?


re.findall ('(ab | cd)', chuỗi) được ['ab', 'cd'] re.findall ('(ab | cd) +', chuỗi) được ['cd']
rock

Câu trả lời:


15

+là một bộ định lượng lặp lại phù hợp với một hoặc nhiều lần. Trong regex (ab|cd)+, bạn đang lặp lại nhóm chụp (ab|cd) bằng +. Điều này sẽ chỉ chụp lần lặp cuối cùng.

Bạn có thể lý do về hành vi này như sau:

Nói chuỗi của bạn là abcdlavà regex là (ab|cd)+. Công cụ Regex sẽ tìm thấy kết quả khớp cho nhóm giữa vị trí 0 và 1 abvà thoát khỏi nhóm chụp. Sau đó, nó nhìn thấy bộ +định lượng và vì vậy cố gắng bắt lại nhóm và sẽ chụp cdgiữa vị trí 2 và 3.


Nếu bạn muốn chụp tất cả các lần lặp, bạn nên chụp nhóm lặp lại thay vì ((ab|cd)+)khớp abcdcd. Bạn có thể làm cho nhóm bên trong không bị bắt vì chúng tôi không quan tâm đến các trận đấu nhóm bên trong với ((?:ab|cd)+)trận đấu nàoabcd

https: //www.THER-expressions.info/captureall.html

Từ Tài liệu,

Giả sử bạn muốn khớp một thẻ như !abc!hoặc !123!. Chỉ có hai điều này là có thể, và bạn muốn nắm bắt abchoặc 123tìm ra thẻ nào bạn có. Điều đó đủ dễ dàng: !(abc|123)!sẽ thực hiện các mẹo.

Bây giờ hãy nói rằng thẻ có thể chứa nhiều chuỗi abc123, như !abc123!hoặc !123abcabc!. Giải pháp nhanh chóng và dễ dàng là !(abc|123)+!. Biểu thức chính quy này sẽ thực sự khớp với các thẻ này. Tuy nhiên, nó không còn đáp ứng yêu cầu của chúng tôi để ghi nhãn của thẻ vào nhóm chụp. Khi regex này khớp !abc123!, nhóm lưu trữ chỉ lưu trữ 123. Khi nó phù hợp !123abcabc!, nó chỉ lưu trữ abc.


bạn có thể liên kết với một số tài liệu để làm rõ thực tế rằng + chỉ chụp lần lặp cuối cùng và nhóm chụp là gì không?
Gulzar

1
@Gulzar, cập nhật câu trả lời. Bạn có thể đọc về các nhóm chụp tại đây - thường xuyên- expressions.info / refcapture.html
Shashank V

@Shashank, cảm ơn, trả lời của bạn chính xác là những gì tôi cần. Xin chân thành cảm ơn
rock

@rock Hãy chấp nhận câu trả lời nếu nó giải quyết được câu hỏi của bạn.
Shashank V

Không cần phải bao quanh toàn bộ regex bằng dấu ngoặc. Chỉ cần '(?:ab|cd)+'làm việc.
Công tước

5

Tôi không biết điều này sẽ làm sáng tỏ mọi thứ nhiều hơn, nhưng hãy thử tưởng tượng những gì xảy ra dưới mui xe một cách đơn giản, chúng ta sẽ tổng hợp những gì xảy ra bằng cách sử dụng khớp

   # group(0) return the matched string the captured groups are returned in groups or you can access them
   # using group(1), group(2).......  in your case there is only one group, one group will capture only 
   # one part so when you do this
   string = 'abcdla'
   print(re.match('(ab|cd)', string).group(0))  # only 'ab' is matched and the group will capture 'ab'
   print(re.match('(ab|cd)+', string).group(0)) # this will match 'abcd'  the group will capture only this part 'cd' the last iteration

findallkhớp và tiêu thụ chuỗi cùng một lúc, hãy tưởng tượng điều gì xảy ra với REGEX này '(ab|cd)':

      'abcdabla' ---> 1:   match: 'ab' |  capture : ab  | left to process:  'cdabla'
      'cdabla'   ---> 2:   match: 'cd' |  capture : cd  | left to process:  'abla'
      'abla'     ---> 3:   match: 'ab' |  capture : ab  | left to process:  'la'
      'la'       ---> 4:   match: '' |  capture : None  | left to process:  ''

      --- final : result captured ['ab', 'cd', 'ab']  

Bây giờ điều tương tự với '(ab|cd)+'

      'abcdabla' ---> 1:   match: 'abcdab' |  capture : 'ab'  | left to process:  'la'
      'la'       ---> 2:   match: '' |  capture : None  | left to process:  ''
      ---> final result :   ['ab']  

Tôi hy vọng điều này sẽ làm rõ một chút.


0

Vì vậy, đối với tôi phần khó hiểu là thực tế rằng

Nếu một hoặc nhiều nhóm có mặt trong mẫu, trả về danh sách các nhóm;

tài liệu

Vì vậy, nó trả lại cho bạn không phải là một trận đấu đầy đủ mà chỉ là một trận đấu. Nếu bạn làm cho nhóm này không bị bắt (re.findall('(?:ab|cd)+', string), nó sẽ trở lại ["abcd"]như tôi dự kiến ​​ban đầu


không chắc chắn là những gì bạn cũng mong đợi hay không
Rịa
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.