chaîne de retour avec première correspondance Regex


90

Je veux obtenir le premier match d'une regex.

Dans ce cas, j'ai une liste:

text = 'aa33bbb44'
re.findall('\d+',text)

[«33», «44»]

Je pourrais extraire le premier élément de la liste:

text = 'aa33bbb44'
re.findall('\d+',text)[0]

«33»

Mais cela ne fonctionne que s'il y a au moins une correspondance, sinon j'obtiendrai une erreur:

text = 'aazzzbbb'
re.findall('\d+',text)[0]

IndexError: index de liste hors de portée

Dans ce cas, je pourrais définir une fonction:

def return_first_match(text):
    try:
        result = re.findall('\d+',text)[0]
    except Exception, IndexError:
        result = ''
    return result

Existe-t-il un moyen d'obtenir ce résultat sans définir une nouvelle fonction?


Pour moi, la réponse acceptée n'a pas fonctionné. J'ai dû supprimer l'accès à l'index du tableau et utiliser len(re.findAll)==0check à la place.
Vishal

Réponses:


104

Vous pouvez intégrer la ''valeur par défaut dans votre regex en ajoutant |$:

>>> re.findall('\d+|$', 'aa33bbb44')[0]
'33'
>>> re.findall('\d+|$', 'aazzzbbb')[0]
''
>>> re.findall('\d+|$', '')[0]
''

Fonctionne également avec re.searchsouligné par d'autres:

>>> re.search('\d+|$', 'aa33bbb44').group()
'33'
>>> re.search('\d+|$', 'aazzzbbb').group()
''
>>> re.search('\d+|$', '').group()
''

Génial, est-ce que search / .group a un avantage sur findall / [0]?
Luis Ramon Ramirez Rodriguez

6
@LuisRamonRamirezRodriguez Eh bien, il peut s'arrêter dès qu'il a trouvé une correspondance, n'a pas à traiter le reste du texte et n'a pas à stocker toutes les correspondances. C'est donc plus efficace. En outre, c'est littéralement "c'est ce que vous voulez" , comme l'a dit @TimPeters. Cela peut être un avantage lorsque vous ou quelqu'un d'autre le lisez à un moment donné et vous demandez "Pourquoi a-t-il été findallutilisé?" .
Stefan Pochmann

43

Si vous n'avez besoin que de la première correspondance, utilisez à la re.searchplace de re.findall:

>>> m = re.search('\d+', 'aa33bbb44')
>>> m.group()
'33'
>>> m = re.search('\d+', 'aazzzbbb')
>>> m.group()
Traceback (most recent call last):
  File "<pyshell#281>", line 1, in <module>
    m.group()
AttributeError: 'NoneType' object has no attribute 'group'

Ensuite, vous pouvez utiliser mcomme condition de vérification comme:

>>> m = re.search('\d+', 'aa33bbb44')
>>> if m:
        print('First number found = {}'.format(m.group()))
    else:
        print('Not Found')


First number found = 33

12

J'irais avec:

r = re.search("\d+", ch)
result = return r.group(0) if r else ""

re.searchne recherche que la première correspondance dans la chaîne de toute façon, donc je pense que cela rend votre intention légèrement plus claire que d'utiliser findall.


7

Vous ne devriez pas utiliser .findall()du tout - .search()c'est ce que vous voulez. Il trouve la correspondance la plus à gauche, ce que vous voulez (ou retourne Nonesi aucune correspondance n'existe).

m = re.search(pattern, text)
result = m.group(0) if m else ""

Que vous souhaitiez mettre cela dans une fonction dépend de vous. Il est inhabituel de vouloir renvoyer une chaîne vide si aucune correspondance n'est trouvée, c'est pourquoi rien de tel n'est intégré. Il est impossible de se demander si .search()elle-même trouve une correspondance (elle renvoie Nonesi ce n'est pas le cas, ou un SRE_Matchobjet si c'était le cas).


3

Tu peux faire:

x = re.findall('\d+', text)
result = x[0] if len(x) > 0 else ''

Notez que votre question n'est pas exactement liée à regex. Au contraire, comment trouver en toute sécurité un élément d'un tableau, s'il n'en a pas.


2
Je remplacerais «len (x)> 0» par simplement «x» ici.
Ulf Aslak

1

Peut-être que cela fonctionnerait un peu mieux dans le cas où une plus grande quantité de données d'entrée ne contient pas votre pièce souhaitée car sauf a un coût plus élevé.

def return_first_match(text):
    result = re.findall('\d+',text)
    result = result[0] if result else ""
    return result
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.