re.findall ('(ab | cd)', string) vs re.findall ('(ab | cd) +', string)

18

Dalam ekspresi reguler Python, saya menghadapi masalah tunggal ini. Bisakah Anda memberikan instruksi tentang perbedaan antara re.findall('(ab|cd)', string)dan 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)

Output aktual adalah:

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

Saya bingung mengapa hasil kedua tidak mengandung 'ab'juga?

batu
sumber
re.findall ('(ab | cd)', string) mendapat ['ab', 'cd'] re.findall ('(ab | cd) +', string) mendapat ['cd']
rock

Jawaban:

15

+adalah pengukur berulang yang cocok dengan satu atau lebih kali. Di regex (ab|cd)+, Anda mengulangi grup tangkap (ab|cd) menggunakan +. Ini hanya akan menangkap iterasi terakhir.

Anda dapat mempertimbangkan perilaku ini sebagai berikut:

Katakan string Anda abcdladan regex (ab|cd)+. Mesin regex akan menemukan kecocokan untuk grup antara posisi 0 dan 1 saat abkeluar dari grup tangkap. Kemudian ia melihat +quantifier dan mencoba menangkap grup lagi dan akan menangkap cdantara posisi 2 dan 3.


Jika Anda ingin menangkap semua iterasi, Anda harus menangkap grup berulang dengan ((ab|cd)+)yang cocok abcddan cd. Anda dapat membuat grup dalam tidak menangkap karena kami tidak peduli dengan pertandingan grup internal ((?:ab|cd)+)yang cocokabcd

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

Dari Documents,

Katakanlah Anda ingin mencocokkan tag suka !abc!atau !123!. Hanya keduanya yang memungkinkan, dan Anda ingin menangkap abcatau 123mencari tahu tag mana yang Anda dapatkan. Itu cukup mudah: !(abc|123)!akan melakukan trik.

Sekarang katakanlah bahwa tag dapat berisi beberapa urutan abcdan 123, seperti !abc123!atau !123abcabc!. Solusi cepat dan mudah adalah !(abc|123)+!. Ekspresi reguler ini memang cocok dengan tag ini. Namun, itu tidak lagi memenuhi persyaratan kami untuk menangkap label tag ke grup penangkapan. Ketika regex ini cocok !abc123!, grup yang menangkap hanya menyimpan 123. Ketika cocok !123abcabc!, itu hanya menyimpan abc.

Shashank V
sumber
dapatkah Anda menautkan ke beberapa dokumen yang menjelaskan fakta bahwa + hanya menangkap iterasi terakhir, dan apa itu grup tangkap?
Gulzar
1
@Gulzar, perbarui jawabannya. Anda dapat membaca tentang menangkap grup di sini - regular-expressions.info/refcapture.html
Shashank V
@Shashank, terima kasih, balasan Anda persis seperti yang saya butuhkan. terima kasih
rock
@rock Silakan terima jawabannya jika itu memecahkan pertanyaan Anda.
Shashank V
Tidak perlu mengelilingi seluruh regex dengan tanda kurung. Hanya '(?:ab|cd)+'akan bekerja.
Dukeling
5

Saya tidak tahu apakah ini akan lebih jelas, tapi mari kita coba bayangkan apa yang terjadi di bawah tenda dengan cara yang sederhana, kita akan menyimpulkan apa yang terjadi dengan menggunakan korek api

   # 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

findallcocokkan dan gunakan string pada saat yang bersamaan mari kita bayangkan apa yang terjadi dengan REGEX ini '(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']  

Sekarang hal yang sama dengan '(ab|cd)+'

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

Saya harap ini membersihkan sedikit.

Charif DZ
sumber
0

Jadi, bagi saya bagian yang membingungkan adalah kenyataan itu

Jika satu atau lebih grup ada dalam pola, kembalikan daftar grup;

docs

jadi itu mengembalikan Anda bukan pertandingan penuh tetapi hanya pertandingan menangkap. Jika Anda membuat grup ini tidak menangkap (re.findall('(?:ab|cd)+', string), itu akan kembali ["abcd"]seperti yang saya harapkan

RiaD
sumber
tidak yakin apa yang Anda juga harapkan atau tidak
RiaD