Python >> Tutoriel Python >  >> Python

Python Re * - Le quantificateur astérisque pour les expressions régulières

Tout informaticien connaît le quantificateur astérisque des expressions régulières. Mais de nombreux non-techniciens le savent aussi. Chaque fois que vous recherchez un fichier texte *.txt sur votre ordinateur, vous utilisez l'opérateur astérisque. Mais comment ça marche ?

Cet article concerne l'astérisque * quantificateur dans la bibliothèque re de Python. Étudiez-le attentivement et maîtrisez cette importante connaissance une fois pour toutes !

Alternativement, vous pouvez également regarder la vidéo où je vous guide tout au long de l'article :

Article connexe : Python Regex Superpower - Le guide ultime

Voulez-vous maîtriser la superpuissance des regex ? Découvrez mon nouveau livre La façon la plus intelligente d'apprendre les expressions régulières en Python avec l'approche innovante en 3 étapes pour un apprentissage actif :(1) étudiez un chapitre de livre, (2) résolvez un puzzle de code et (3) regardez une vidéo de chapitre éducatif.

Qu'est-ce que le Python Re * Quantifier ?

Lorsqu'il est appliqué à l'expression régulière A , A* de Python le quantificateur correspond à zéro ou plusieurs occurrences de A . L'étoile * le symbole est appelé astérisque ou opérateur générique et il s'applique à l'expression régulière précédente. Par exemple, l'expression régulière 'yes*' correspond aux chaînes 'ye' , 'yes' , et 'yesssssss' mais pas la chaîne vide '' .

Étudions deux exemples de base pour vous aider à mieux comprendre. Les obtenez-vous tous ?

>>> import re
>>> text = 'finxter for fast and fun python learning'
>>> re.findall('f.* ', text)
['finxter for fast and fun python ']
>>> re.findall('f.*? ', text)
['finxter ', 'for ', 'fast ', 'fun ']
>>> re.findall('f[a-z]*', text)
['finxter', 'for', 'fast', 'fun']
>>> 

Ne vous inquiétez pas si vous avez eu des problèmes pour comprendre ces exemples. Vous en apprendrez plus sur eux ensuite. Voici le premier exemple :

Exemple d'astérisque gourmand

>>> re.findall('f.* ', text)
['finxter for fast and fun python ']

Vous utilisez le re.findall() méthode. Au cas où vous ne le sauriez pas, voici la définition tirée de l'article du blog Finxter :

Le re.findall(pattern, string) la méthode trouve toutes les occurrences du pattern dans le string et renvoie une liste de toutes les sous-chaînes correspondantes.

Veuillez consulter l'article du blog pour apprendre tout ce que vous devez savoir sur cette méthode Python fondamentale.

Le premier argument est le modèle d'expression régulière 'f.* ' . Le deuxième argument est la chaîne à rechercher pour le modèle. En clair, vous voulez trouver tous les modèles dans la chaîne qui commencent par le caractère 'f' , suivi d'un nombre arbitraire de caractères facultatifs, suivi d'un espace vide.

Le findall() la méthode renvoie une seule sous-chaîne correspondante :'finxter for fast and fun python ' . Le quantificateur astérisque * est gourmand. Cela signifie qu'il essaie de faire correspondre autant d'occurrences que possible de la regex précédente. Donc, dans notre cas, il veut faire correspondre autant de caractères arbitraires que possible afin que le modèle soit toujours mis en correspondance. Par conséquent, le moteur regex "consomme" la phrase entière.

Exemple d'astérisque non gourmand

Mais que se passe-t-il si vous voulez trouver tous les mots commençant par un 'f' ? En d'autres termes :comment faire correspondre le texte avec un opérateur astérisque non gourmand ?

Le deuxième exemple est le suivant :

>>> re.findall('f.*? ', text)
['finxter ', 'for ', 'fast ', 'fun ']

Dans cet exemple, vous regardez un modèle similaire avec une seule différence :vous utilisez l'opérateur astérisque non gourmand *? . Vous voulez trouver toutes les occurrences du caractère 'f' suivi d'un nombre arbitraire de caractères (mais aussi peu que possible), suivi d'un espace vide.

Par conséquent, le moteur regex trouve quatre correspondances :les chaînes 'finxter ' , 'for ' , 'fast ' , et 'fun ' .

Astérisque + Exemple de classe de caractères

Le troisième exemple est le suivant :

>>> re.findall('f[a-z]*', text)
['finxter', 'for', 'fast', 'fun']

Cette expression régulière réalise presque la même chose :trouver tous les mots commençant par f . Mais vous utilisez le quantificateur astérisque en combinaison avec une classe de caractères qui définit spécifiquement quels caractères sont des correspondances valides.

Dans la classe de caractères, vous pouvez définir des plages de caractères. Par exemple, la plage de caractères [a-z] correspond à un caractère minuscule dans l'alphabet tandis que la plage de caractères [A-Z] correspond à un caractère majuscule de l'alphabet.

Mais notez que l'espace vide ne fait pas partie de la classe de caractères, il ne sera donc pas mis en correspondance s'il apparaît dans le texte. Ainsi, le résultat est la même liste de mots commençant par le caractère 'f' :'finxter ' , 'for ' , 'fast ' , et 'fun ' .

Et si vous voulez faire correspondre le caractère astérisque lui-même ?

Vous savez que le quantificateur astérisque correspond à un nombre arbitraire de l'expression régulière précédente. Mais que se passe-t-il si vous recherchez le caractère astérisque (ou étoile) lui-même ? Comment pouvez-vous le rechercher dans une chaîne ?

La réponse est simple :échappez le caractère astérisque de votre expression régulière à l'aide de la barre oblique inverse. En particulier, utilisez '\*' au lieu de '*' . Voici un exemple :

>>> import re
>>> text = 'Python is ***great***'
>>> re.findall('\*', text)
['*', '*', '*', '*', '*', '*']
>>> re.findall('\**', text)
['', '', '', '', '', '', '', '', '', '', '***', '', '', '', '', '', '***', '']
>>> re.findall('\*+', text)
['***', '***']

Vous trouvez toutes les occurrences du symbole étoile dans le texte en utilisant la regex '\*' . Par conséquent, si vous utilisez la regex '\**' , vous recherchez un nombre arbitraire d'occurrences du symbole astérisque (y compris zéro occurrence). Et si vous souhaitez rechercher le nombre maximal d'occurrences de symboles astérisques suivants dans un texte, vous utiliserez la regex '\*+' .

[Collection] Quels sont les différents quantificateurs Python Re ?

Le quantificateur astérisque—Python concernant * — n'est qu'un des nombreux opérateurs regex. Si vous voulez utiliser (et comprendre) les expressions régulières dans la pratique, vous devrez toutes les connaître par cœur !

Passons donc aux autres opérateurs :

Une expression régulière est un concept vieux de plusieurs décennies en informatique. Inventé dans les années 1950 par le célèbre mathématicien Stephen Cole Kleene, les décennies d'évolution ont apporté une grande variété d'opérations. La collecte de toutes les opérations et la rédaction d'une liste complète aboutiraient à un livre très épais et illisible en soi.

Heureusement, vous n'avez pas besoin d'apprendre toutes les expressions régulières avant de pouvoir commencer à les utiliser dans vos projets de code pratiques. Ensuite, vous obtiendrez un aperçu rapide et grossier des opérations regex les plus importantes et comment les utiliser en Python. Dans les chapitres suivants, vous les étudierez ensuite en détail, avec de nombreuses applications pratiques et des puzzles de code.

Voici les quantificateurs de regex les plus importants :

Quantificateur Description Exemple
. Le caractère générique ('dot') correspond à n'importe quel caractère d'une chaîne à l'exception du caractère de saut de ligne '\n' . Regex '...' correspond à tous les mots de trois caractères tels que 'abc' , 'cat' , et 'dog' .
* Le zéro ou plus l'astérisque correspond à un nombre arbitraire d'occurrences (y compris zéro occurrence) de l'expression régulière précédente. Regex 'cat*' correspond aux chaînes 'ca' , 'cat' , 'catt' , 'cattt' , et 'catttttttt' . —
? Le zéro ou un correspond (comme son nom l'indique) à zéro ou à une occurrence de la regex immédiatement précédente. Regex 'cat?' correspond aux deux chaînes 'ca' et 'cat' — mais pas 'catt' , 'cattt' , et 'catttttttt' .
+ Le au moins un correspond à une ou plusieurs occurrences de la regex immédiatement précédente. Regex 'cat+' ne correspond pas à la chaîne 'ca' mais correspond à toutes les chaînes avec au moins un caractère de fin 't' comme 'cat' , 'catt' , et 'cattt' .
^ Le début de chaîne correspond au début d'une chaîne. Regex '^p' correspond aux chaînes 'python' et 'programming' mais pas 'lisp' et 'spying' où le caractère 'p' ne se produit pas au début de la chaîne.
$ La fin de chaîne correspond à la fin d'une chaîne. Regex 'py$' correspondrait aux chaînes ' main.py' et ' pypy' mais pas les chaînes 'python' et 'pypi' .
A|B Le OU correspond à la regex A ou à la regex B. Notez que l'intuition est assez différente de l'interprétation standard de l'opérateur or qui peut également satisfaire les deux conditions. Regex ' (bonjour)|(salut)' correspond aux chaînes 'hello world' et 'hi python' . Cela n'aurait aucun sens d'essayer de faire correspondre les deux en même temps.
AB Le ET correspond d'abord à la regex A et ensuite à la regex B, dans cette séquence. On l'a déjà vu trivialement dans la regex 'ca' qui correspond à la première expression régulière 'c' et deuxième regex 'a' .

Notez que j'ai donné aux opérateurs ci-dessus des noms plus significatifs (en gras) afin que vous puissiez saisir immédiatement le but de chaque regex. Par exemple, le ^ L'opérateur est généralement désigné par l'opérateur "caret". Ces noms ne sont pas descriptifs, j'ai donc trouvé des mots plus proches de la maternelle, tels que l'opérateur "début de chaîne".

Nous avons déjà vu de nombreux exemples, mais plongeons-nous encore plus !

import re

text = '''
    Ha! let me see her: out, alas! he's cold:
    Her blood is settled, and her joints are stiff;
    Life and these lips have long been separated:
    Death lies on her like an untimely frost
    Upon the sweetest flower of all the field.
'''

print(re.findall('.a!', text))
'''
Finds all occurrences of an arbitrary character that is
followed by the character sequence 'a!'.
['Ha!']
'''

print(re.findall('is.*and', text))
'''
Finds all occurrences of the word 'is',
followed by an arbitrary number of characters
and the word 'and'.
['is settled, and']
'''

print(re.findall('her:?', text))
'''
Finds all occurrences of the word 'her',
followed by zero or one occurrences of the colon ':'.
['her:', 'her', 'her']
'''

print(re.findall('her:+', text))
'''
Finds all occurrences of the word 'her',
followed by one or more occurrences of the colon ':'.
['her:']
'''


print(re.findall('^Ha.*', text))
'''
Finds all occurrences where the string starts with
the character sequence 'Ha', followed by an arbitrary
number of characters except for the new-line character. 
Can you figure out why Python doesn't find any?
[]
'''

print(re.findall('n$', text))
'''
Finds all occurrences where the new-line character 'n'
occurs at the end of the string.
['n']
'''

print(re.findall('(Life|Death)', text))
'''
Finds all occurrences of either the word 'Life' or the
word 'Death'.
['Life', 'Death']
'''

Dans ces exemples, vous avez déjà vu le symbole spécial '\n' qui désigne le caractère de nouvelle ligne en Python (et la plupart des autres langages). Il existe de nombreux caractères spéciaux, spécialement conçus pour les expressions régulières. Ensuite, nous découvrirons les symboles spéciaux les plus importants.

Quelle est la différence entre Python Re * et ? Quantificateurs ?

Vous pouvez lire le Python Re A? quantificateur en tant que zéro ou un regex :la regex précédente A est mis en correspondance zéro fois ou exactement une fois. Mais il n'est pas mis en correspondance plus souvent.

De manière analogue, vous pouvez lire le Python Re A* opérateur en tant que regex zéro ou plus (je sais que ça sonne un peu maladroit) :la regex précédente A correspond un nombre arbitraire de fois.

Voici un exemple qui montre la différence :

>>> import re
>>> re.findall('ab?', 'abbbbbbb')
['ab']
>>> re.findall('ab*', 'abbbbbbb')
['abbbbbbb']

L'expression régulière 'ab?' correspond au caractère 'a' dans la chaîne, suivi du caractère 'b' s'il existe (ce qu'il fait dans le code).

L'expression régulière 'ab*' correspond au caractère 'a' dans la chaîne, suivi d'autant de caractères 'b' que possible.

Quelle est la différence entre les quantificateurs Python Re * et + ?

Vous pouvez lire le Python Re A* quantificateur en tant que zéro ou plus regex :la regex précédente A correspond un nombre arbitraire de fois.

De manière analogue, vous pouvez lire le Python Re A+ opérateur comme au moins une fois regex :la regex précédente A est mis en correspondance un nombre arbitraire de fois également, mais au moins une fois.

Voici un exemple qui montre la différence :

>>> import re
>>> re.findall('ab*', 'aaaaaaaa')
['a', 'a', 'a', 'a', 'a', 'a', 'a', 'a']
>>> re.findall('ab+', 'aaaaaaaa')
[]

L'expression régulière 'ab*' correspond au caractère 'a' dans la chaîne, suivi d'un nombre arbitraire d'occurrences du caractère 'b' . La sous-chaîne 'a' correspond parfaitement à cette formulation. Par conséquent, vous constatez que l'expression régulière correspond huit fois dans la chaîne.

L'expression régulière 'ab+' correspond au caractère 'a' , suivi d'autant de caractères 'b' que possible, mais au moins un. Cependant, le caractère 'b' n'existe pas donc il n'y a pas de correspondance.

Qu'est-ce que Python Re *? , +? , ?? Quantificateurs ?

Vous avez découvert les trois quantificateurs :

  • Le quantificateur A* correspond à un nombre arbitraire de motifs A .
  • Le quantificateur A+ correspond à au moins un motif A .
  • Le quantificateur A? correspond au modèle zéro ou un A .

Ces trois-là sont tous gourmands :ils correspondent à autant d'occurrences du modèle que possible. Voici un exemple qui montre leur gourmandise :

>>> import re
>>> re.findall('a*', 'aaaaaaa')
['aaaaaaa', '']
>>> re.findall('a+', 'aaaaaaa')
['aaaaaaa']
>>> re.findall('a?', 'aaaaaaa')
['a', 'a', 'a', 'a', 'a', 'a', 'a', '']

Le code montre que les trois quantificateurs * , + , et ? correspondre à autant de 'a' caractères que possible.

Donc, la question logique est :comment faire correspondre le moins possible ? Nous appelons cela non gourmand correspondant à. Vous pouvez ajouter le point d'interrogation après les quantificateurs respectifs pour indiquer au moteur de regex que vous avez l'intention de faire correspondre le moins de modèles possible :*? , +? , et ?? .

Voici le même exemple mais avec les quantificateurs non gourmands :

>>> import re
>>> re.findall('a*?', 'aaaaaaa')
['', 'a', '', 'a', '', 'a', '', 'a', '', 'a', '', 'a', '', 'a', '']
>>> re.findall('a+?', 'aaaaaaa')
['a', 'a', 'a', 'a', 'a', 'a', 'a']
>>> re.findall('a??', 'aaaaaaa')
['', 'a', '', 'a', '', 'a', '', 'a', '', 'a', '', 'a', '', 'a', '']

Dans ce cas, le code montre que les trois quantificateurs *? , +? , et ?? correspond à aussi peu de 'a' personnages que possible.

Méthodes Re associées

Il existe cinq méthodes d'expression régulière importantes que vous devez maîtriser :

  • Le re.findall(pattern, string) La méthode renvoie une liste de correspondances de chaînes. Pour en savoir plus, consultez le didacticiel de notre blog.
  • Le re.search(pattern, string) La méthode renvoie un objet match de la première correspondance. Pour en savoir plus, consultez le didacticiel de notre blog.
  • Le re.match(pattern, string) La méthode renvoie un objet match si l'expression régulière correspond au début de la chaîne. Pour en savoir plus, consultez le didacticiel de notre blog.
  • Le re.fullmatch(pattern, string) La méthode renvoie un objet match si l'expression régulière correspond à la chaîne entière. Pour en savoir plus, consultez le didacticiel de notre blog.
  • Le re.compile(pattern) La méthode prépare le modèle d'expression régulière et renvoie un objet regex que vous pouvez utiliser plusieurs fois dans votre code. Pour en savoir plus, consultez le didacticiel de notre blog.
  • Le re.split(pattern, string) La méthode renvoie une liste de chaînes en faisant correspondre toutes les occurrences du modèle dans la chaîne et en divisant la chaîne le long de celles-ci. Pour en savoir plus, consultez le didacticiel de notre blog.
  • Le re.sub(pattern, repl, string, count=0, flags=0) La méthode renvoie une nouvelle chaîne où toutes les occurrences du modèle dans l'ancienne chaîne sont remplacées par repl . Pour en savoir plus, consultez le didacticiel de notre blog.

Ces sept méthodes représentent 80 % de ce que vous devez savoir pour démarrer avec la fonctionnalité d'expression régulière de Python.