re.findall ('(ab | cd)', สตริง) vs re.findall ('(ab | cd) +', สตริง)


18

ในนิพจน์ทั่วไปของ Python ฉันพบปัญหาเอกพจน์นี้ คุณสามารถให้คำแนะนำเกี่ยวกับความแตกต่างระหว่าง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)

ผลลัพธ์ที่แท้จริงคือ:

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

ฉันสับสนว่าทำไมผลลัพธ์ที่สองจึงไม่มี'ab'เช่นกัน


re.findall ('(ab | cd)', สตริง) ได้รับ ['ab', 'cd'] re.findall ('(ab | cd) +', สตริง) รับ ['cd']
rock

คำตอบ:


15

+เป็นตัวระบุปริมาณซ้ำที่ตรงกับหนึ่งครั้งขึ้นไป ใน regex (ab|cd)+คุณกำลังทำซ้ำกลุ่มการจับภาพ (ab|cd)โดยใช้ + สิ่งนี้จะจับการวนซ้ำล่าสุดเท่านั้น

คุณสามารถให้เหตุผลเกี่ยวกับพฤติกรรมนี้ดังนี้:

Say สตริงของคุณabcdlaและ regex (ab|cd)+คือ เอ็นจิ้น Regex จะค้นหาการจับคู่สำหรับกลุ่มระหว่างตำแหน่ง 0 และ 1 ตามabและออกจากกลุ่มการดักจับ จากนั้นก็จะเห็น+ปริมาณและพยายามจับกลุ่มอีกครั้งและจะจับภาพcdระหว่างตำแหน่ง 2 และ 3


หากคุณต้องการที่จะจับซ้ำที่ทุกท่านควรจะจับภาพกลุ่มซ้ำแทนด้วย((ab|cd)+)ซึ่งตรงและabcd cdคุณสามารถทำให้กลุ่มภายในไม่จับภาพได้เนื่องจากเราไม่สนใจการจับคู่กลุ่มภายในที่มีการ((?:ab|cd)+)จับคู่abcd

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

จากเอกสาร

สมมติว่าคุณต้องการจับคู่แท็กเหมือนหรือ!abc! !123!มีเพียงสองสิ่งนี้เท่านั้นที่เป็นไปได้และคุณต้องการจับภาพabcหรือ123เพื่อหาว่าคุณได้รับแท็กใด ง่ายพอ: !(abc|123)!จะทำเคล็ดลับ

ตอนนี้ขอบอกว่าแท็กสามารถมีหลายลำดับabcและ 123เหมือนหรือ!abc123! วิธีการแก้ปัญหาที่ง่ายและรวดเร็วคือ!123abcabc! !(abc|123)+!นิพจน์ทั่วไปนี้จะตรงกับแท็กเหล่านี้ อย่างไรก็ตามไม่ตรงกับความต้องการของเราในการจับฉลากของแท็กในกลุ่มการจับภาพ เมื่อเป็นเช่นนี้การแข่งขัน regex !abc123!, 123จับร้านค้าเพียงกลุ่มเดียว เมื่อมันตรงกับมันร้านค้าเท่านั้น!123abcabc!abc


คุณสามารถเชื่อมโยงไปยังเอกสารบางฉบับที่ทำให้เห็นได้ชัดเจนว่า + จับเฉพาะการวนซ้ำล่าสุดและกลุ่มการจับภาพคืออะไร
Gulzar

1
@Gulzar อัปเดตคำตอบ คุณสามารถอ่านเกี่ยวกับกลุ่มการจับกุมได้ที่นี่ - regular-expressions.info/refcapture.html
Shashank V

@Shashank ขอบคุณคำตอบของคุณคือสิ่งที่ฉันต้องการ ขอบคุณอย่างจริงใจ
rock

@ ร็อคโปรดยอมรับคำตอบหากตอบคำถามของคุณ
Shashank V

ไม่จำเป็นต้องล้อมรอบ regex ทั้งหมดด้วยวงเล็บ เพียงแค่'(?:ab|cd)+'จะทำงาน
Dukeling

5

ฉันไม่รู้ว่าจะล้างสิ่งต่าง ๆ อีกหรือเปล่า แต่ลองจินตนาการว่าเกิดอะไรขึ้นภายใต้ประทุนด้วยวิธีง่ายๆเราจะสรุปสิ่งที่เกิดขึ้นโดยใช้การจับคู่

   # 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

findallจับคู่และใช้สตริงในเวลาเดียวกันลองจินตนาการว่าเกิดอะไรขึ้นกับ REGEX นี้'(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']  

ตอนนี้สิ่งเดียวกันกับ '(ab|cd)+'

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

ฉันหวังว่านี่จะล้างสิ่งเล็กน้อย


0

ดังนั้นสำหรับฉันส่วนที่สับสนคือความจริงที่ว่า

หากมีหนึ่งกลุ่มขึ้นไปอยู่ในรูปแบบให้ส่งคืนรายการกลุ่ม

เอกสาร

ดังนั้นมันจึงไม่ใช่การจับคู่แบบเต็ม แต่เป็นการจับภาพเท่านั้น หากคุณทำให้กลุ่มนี้ไม่สามารถจับภาพ(re.findall('(?:ab|cd)+', string)ได้มันจะกลับมา["abcd"]ตามที่ฉันคาดไว้ในตอนแรก


ไม่แน่ใจว่าเป็นสิ่งที่คุณคาดหวังหรือไม่
RiaD
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.