2010-03-31 13 views
33

Existe-t-il un moyen en Python d'accéder à des groupes de correspondance sans créer explicitement un objet de correspondance (ou un autre moyen d'embellir l'exemple ci-dessous)?Groupes de correspondance en Python

Voici un exemple pour clarifier ma motivation pour la question:

code suivant perl

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 en cascade, correspondre à la création d'objet).

+0

double: http://stackoverflow.com/questions/122277/ how-do-you-translate-this-expression-régulière idiome-de-perl-en-python –

+0

Avertissement: Python re.match() correspond spécifiquement au début de la cible. Ainsi re.match ("J'aime (\ w +)", "Oh, comme je t'aime") ne correspondrait pas. Vous voulez soit utiliser re.search() ou préfixer explicitement l'expression régulière avec des motifs génériques appropriés pour re.match (". * J'aime (\ w +)", ...) –

+0

@Jim Dennis: merci de le signaler; J'ai adapté l'exemple de python en conséquence – Curd

Répondre

31

Vous pouvez créer une petite classe qui renvoie le résultat booléen d'appeler match et conserve les groupes appariés pour 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 "???" 
+0

+1 bonne solution; bien qu'un peu verbeux – Curd

+1

Il peut être verbeux, mais vous placerez la classe REMatcher dans un joli module que vous importerez quand vous en aurez besoin. Vous ne poseriez pas cette question pour un problème qui ne reviendra pas dans le futur, n'est-ce pas? – tzot

+1

@ ΤΖΩΤΖΙΟΥ: Je suis d'accord; mais, pourquoi une telle classe dans le module n'est pas encore? – Curd

13

moins efficace, mais plus simple prospectifs:

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 les choses Perl est la mise à jour implicite d'une variable cachée. C'est simplement difficile à réaliser en Python car vous devez avoir une instruction d'assignation pour mettre à jour toutes les variables.

La version avec moins de répétitions (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 gens 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 

Ceci est à peine utile de mentionner, sauf qu'il ne venir parfois à partir de programmeurs Perl.

+3

@ S.Lott: ok, votre solution évite la if-else-cascade, mais au frais de faire des correspondances inutiles (m1 et m2 n'est pas nécessaire si m0 correspond) C'est pourquoi je ne suis pas vraiment satisfait de cette solution. – Curd

+2

+1 J'aime mieux la deuxième version ... – Curd

+0

+1 pour votre deuxième moyen –

3

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:] 
1

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 utiliser 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] 

Il est un peu maladroit, mais il fait le travail.

Questions connexes