web-dev-qa-db-fra.com

Faire correspondre les groupes dans Python

Existe-t-il un moyen dans Python pour accéder aux groupes de correspondance sans créer explicitement un objet de correspondance (ou une autre façon d'embellir l'exemple ci-dessous)?

Voici un exemple pour clarifier ma motivation pour la question:

Code Perl suivant

if    ($statement =~ /I love (\w+)/) {
  print "He loves $1\n";
}
elsif ($statement =~ /Ich liebe (\w+)/) {
  print "Er liebt $1\n";
}
elsif ($statement =~ /Je t\'aime (\w+)/) {
  print "Il aime $1\n";
}

traduit en Python

m = re.search("I love (\w+)", statement)
if m:
  print "He loves",m.group(1)
else:
  m = re.search("Ich liebe (\w+)", statement)
  if m:
    print "Er liebt",m.group(1)
  else:
    m = re.search("Je t'aime (\w+)", statement)
    if m:
      print "Il aime",m.group(1)

semble très maladroit (if-else-cascade, correspond à la création d'objet).

43
Curd

Vous pouvez créer une petite classe qui renvoie le résultat booléen de l'appel de match, et conserve les groupes correspondants pour une récupération ultérieure:

import re

class REMatcher(object):
    def __init__(self, matchstring):
        self.matchstring = matchstring

    def match(self,regexp):
        self.rematch = re.match(regexp, self.matchstring)
        return bool(self.rematch)

    def group(self,i):
        return self.rematch.group(i)


for statement in ("I love Mary", 
                  "Ich liebe Margot", 
                  "Je t'aime Marie", 
                  "Te amo Maria"):

    m = REMatcher(statement)

    if m.match(r"I love (\w+)"): 
        print "He loves",m.group(1) 

    Elif m.match(r"Ich liebe (\w+)"):
        print "Er liebt",m.group(1) 

    Elif m.match(r"Je t'aime (\w+)"):
        print "Il aime",m.group(1) 

    else: 
        print "???"
36
PaulMcG

Moins efficace, mais plus simple:

m0 = re.match("I love (\w+)", statement)
m1 = re.match("Ich liebe (\w+)", statement)
m2 = re.match("Je t'aime (\w+)", statement)
if m0:
  print "He loves",m0.group(1)
Elif m1:
  print "Er liebt",m1.group(1)
Elif m2:
  print "Il aime",m2.group(1)

Le problème avec le truc Perl est la mise à jour implicite de certaines variables cachées. C'est tout simplement difficile à réaliser dans Python car vous devez avoir une instruction d'affectation pour mettre à jour réellement toutes les variables.

La version avec moins de répétition (et une meilleure efficacité) est la suivante:

pats = [
    ("I love (\w+)", "He Loves {0}" ),
    ("Ich liebe (\w+)", "Er Liebe {0}" ),
    ("Je t'aime (\w+)", "Il aime {0}")
 ]
for p1, p3 in pats:
    m= re.match( p1, statement )
    if m:
        print p3.format( m.group(1) )
        break

Une variation mineure que certains folkloriques Perl préfèrent:

pats = {
    "I love (\w+)" : "He Loves {0}",
    "Ich liebe (\w+)" : "Er Liebe {0}",
    "Je t'aime (\w+)" : "Il aime {0}",
}
for p1 in pats:
    m= re.match( p1, statement )
    if m:
        print pats[p1].format( m.group(1) )
        break

Cela ne vaut guère la peine d'être mentionné, sauf que cela vient parfois des programmeurs Perl.

20
S.Lott

ce n'est pas une solution regex.

alist={"I love ":""He loves"","Je t'aime ":"Il aime","Ich liebe ":"Er liebt"}
for k in alist.keys():
    if k in statement:
       print alist[k],statement.split(k)[1:]
4
ghostdog74

Vous pouvez créer une fonction d'assistance:

def re_match_group(pattern, str, out_groups):
    del out_groups[:]
    result = re.match(pattern, str)
    if result:
        out_groups[:len(result.groups())] = result.groups()
    return result

Et puis utilisez-le comme ceci:

groups = []
if re_match_group("I love (\w+)", statement, groups):
    print "He loves", groups[0]
Elif re_match_group("Ich liebe (\w+)", statement, groups):
    print "Er liebt", groups[0]
Elif re_match_group("Je t'aime (\w+)", statement, groups):
    print "Il aime", groups[0]

C'est un peu maladroit, mais ça fait le travail.

1
Adam Rosenfield

À partir de Python 3.8 Et de l'introduction de expressions d'affectation (PEP 572) (opérateur :=), Nous pouvons maintenant capturer la valeur de condition re.search(pattern, statement) dans une variable (disons tout match) afin de vérifier si ce n'est pas None puis de la réutiliser dans le corps de la condition:

if match := re.search('I love (\w+)', statement):
  print(f'He loves {match.group(1)}')
Elif match := re.search("Ich liebe (\w+)", statement):
  print(f'Er liebt {match.group(1)}')
Elif match := re.search("Je t'aime (\w+)", statement):
  print(f'Il aime {match.group(1)}')
0
Xavier Guihot