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


18

In un'espressione regolare di Python, ho riscontrato questo singolare problema. Potresti dare istruzioni sulle differenze tra re.findall('(ab|cd)', string)e 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)

L'output effettivo è:

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

Sono confuso sul perché il secondo risultato non contenga 'ab'anche?


re.findall ('(ab | cd)', stringa) ottiene ['ab', 'cd'] re.findall ('(ab | cd) +', stringa) ottiene ['cd']
rock

Risposte:


15

+è un quantificatore ripetuto che corrisponde una o più volte. Nella regex (ab|cd)+, stai ripetendo il gruppo di acquisizione (ab|cd) usando +. Questo catturerà solo l'ultima iterazione.

Puoi ragionare su questo comportamento come segue:

Dì che la tua stringa è abcdlae regex lo è (ab|cd)+. Il motore Regex troverà una corrispondenza per il gruppo tra le posizioni 0 e 1 abe uscirà dal gruppo di acquisizione. Quindi vede +quantificatore e quindi tenta di acquisire nuovamente il gruppo e catturerà cdtra le posizioni 2 e 3.


Se si desidera acquisire tutte le iterazioni, è necessario acquisire il gruppo ripetuto anziché le ((ab|cd)+)corrispondenze abcde cd. Puoi fare in modo che il gruppo interno non si catturi perché non ci importa delle partite del gruppo interno con ((?:ab|cd)+)quali partiteabcd

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

Da the Docs,

Supponiamo che tu voglia abbinare un tag come !abc!o !123!. Solo questi due sono possibili e tu vuoi catturare il abco 123per capire quale tag hai. È abbastanza facile: !(abc|123)!farà il trucco.

Ora diciamo che il tag può contenere più sequenze di abce 123, come !abc123!o !123abcabc!. La soluzione semplice e veloce è !(abc|123)+!. Questa espressione regolare corrisponderà effettivamente a questi tag. Tuttavia, non soddisfa più il nostro requisito di acquisire l'etichetta del tag nel gruppo di acquisizione. Quando questa regex corrisponde !abc123!, viene memorizzato solo il gruppo di acquisizione 123. Quando corrisponde !123abcabc!, memorizza solo abc.


puoi collegarti ad alcuni documenti chiarendo che + cattura solo l'ultima iterazione e che cos'è un gruppo di acquisizione?
Gulzar

1
@Gulzar, aggiornata la risposta. Puoi leggere i gruppi di acquisizione qui - regular-expressions.info/refcapture.html
Shashank V

@Shan, grazie, la tua risposta è esattamente ciò di cui ho bisogno. sinceramente grazie
rock

@rock Si prega di accettare la risposta se ha risolto la tua domanda.
Shashank V

Non è necessario circondare l'intera regex con parentesi. Funzionerà '(?:ab|cd)+'e basta .
Dukeling

5

Non so se questo chiarirà di più le cose, ma proviamo a immaginare cosa succede sotto il cofano in modo semplice, riassumeremo cosa succede usando match

   # 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

findallabbina e consuma la stringa allo stesso tempo, immaginiamo cosa succede con questo 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']  

Ora la stessa cosa con '(ab|cd)+'

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

Spero che questo chiarisca un po 'la cosa.


0

Quindi, per me parte confusa era il fatto

Se uno o più gruppi sono presenti nel modello, restituisce un elenco di gruppi;

docs

quindi ti restituisce non una partita completa, ma solo una partita di una cattura. Se fai in modo che questo gruppo non venga catturato (re.findall('(?:ab|cd)+', string), tornerà ["abcd"]come inizialmente previsto


non sono sicuro di quello che ti aspettavi o no
RiaD
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.