Python >> Tutoriel Python >  >> Python

Python Re Question Mark (?):Correspondance facultative

Félicitations, vous êtes sur le point d'apprendre l'un des opérateurs regex les plus fréquemment utilisés :le quantificateur de point d'interrogation A? .

En particulier, cet article concerne le ? quantificateur dans la bibliothèque re de Python. Vous pouvez également regarder la vidéo explicative pendant que vous parcourez le didacticiel :

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 Python Re ? Quantificateur

Lorsqu'il est appliqué à l'expression régulière A , A? de Python le quantificateur correspond à zéro ou à une occurrence de A . Par exemple, l'expression régulière 'hey?' correspond aux deux chaînes 'he' et 'hey' , mais pas la chaîne vide '' . C'est parce que le ? le quantificateur ne s'applique pas à l'ensemble de la regex 'hey' mais uniquement à la regex précédente 'y' .

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

>>> import re
>>>
>>> re.findall('aa[cde]?', 'aacde aa aadcde')
['aac', 'aa', 'aad']
>>>
>>> re.findall('aa?', 'accccacccac')
['a', 'a', 'a']
>>>
>>> re.findall('[cd]?[cde]?', 'ccc dd ee')
['cc', 'c', '', 'dd', '', 'e', 'e', '']

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 :

>>> re.findall('aa[cde]?', 'aacde aa aadcde')
['aac', 'aa', 'aad']

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 'aa[cde]?' . Le deuxième argument est la chaîne à rechercher pour le modèle. En clair, vous voulez trouver tous les modèles qui commencent par deux 'a' caractères, suivis d'un caractère facultatif, qui peut être soit 'c' , 'd' , ou 'e' .

Le findall() La méthode renvoie trois sous-chaînes correspondantes :

  • Tout d'abord, chaîne 'aac' correspond au motif. Une fois que Python a consommé la sous-chaîne correspondante, la sous-chaîne restante est 'de aa aadcde' .
  • Deuxièmement, chaîne 'aa' correspond au motif. Python le consomme, ce qui conduit à la sous-chaîne restante ' aadcde' .
  • Troisièmement, chaîne 'aad' correspond au modèle dans la sous-chaîne restante. Ce qui reste est 'cde' qui ne contient plus de sous-chaîne correspondante.

Le deuxième exemple est le suivant :

>>> re.findall('aa?', 'accccacccac')
['a', 'a', 'a']

Dans cet exemple, vous regardez le modèle simple 'aa?' . Vous voulez trouver toutes les occurrences du caractère 'a' suivi d'un deuxième 'a' facultatif . Mais sachez que le deuxième 'a' facultatif n'est pas nécessaire pour que le motif corresponde.

Par conséquent, le moteur regex trouve trois correspondances :les caractères 'a' .

Le troisième exemple est le suivant :

>>> re.findall('[cd]?[cde]?', 'ccc dd ee')
['cc', 'c', '', 'dd', '', 'e', 'e', '']

Ce modèle de regex semble compliqué :'[cd]?[cde]?' . Mais est-ce vraiment ?

Décomposons-le étape par étape :

  • La première partie de la regex [cd]? définit une classe de caractères [cd] qui se lit comme "match soit c ou d “. Le quantificateur de point d'interrogation indique que vous souhaitez faire correspondre une ou zéro occurrence de ce modèle.
  • La deuxième partie de la regex [cde]? définit une classe de caractères [cde] qui se lit comme "match soit c , d , ou e “. Encore une fois, le point d'interrogation indique l'exigence de correspondance zéro ou un.

Comme les deux parties sont facultatives, la chaîne vide correspond au modèle regex. Cependant, le moteur Python regex essaie autant que possible .

Ainsi, le moteur de regex effectue les étapes suivantes :

  • La première correspondance dans la chaîne 'ccc dd ee' est 'cc' . Le moteur regex consomme la sous-chaîne correspondante, donc la chaîne 'c dd ee' reste.
  • La deuxième correspondance dans la chaîne restante est le caractère 'c' . L'espace vide ' ' ne correspond pas à la regex donc la deuxième partie de la regex [cde] ne correspond pas. En raison du quantificateur de point d'interrogation, cela convient au moteur de regex. La chaîne restante est ' dd ee' .
  • La troisième correspondance est la chaîne vide '' . Bien sûr, Python n'essaie pas de faire correspondre deux fois la même position. Ainsi, il passe au traitement de la chaîne restante 'dd ee' .
  • La quatrième correspondance est la chaîne 'dd' . La chaîne restante est ' ee' .
  • La cinquième correspondance est la chaîne '' . La chaîne restante est 'ee' .
  • La sixième correspondance est la chaîne 'e' . La chaîne restante est 'e' .
  • La septième correspondance est la chaîne 'e' . La chaîne restante est '' .
  • La huitième correspondance est la chaîne '' . Il ne reste rien.

C'était le plus compliqué de nos exemples. Félicitations si vous avez bien compris !

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

Le quantificateur de point d'interrogation—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 :

Plongeons-nous donc dans les autres expressions régulières :

Quantificateur Description Exemple
. Le caractère générique ('point') 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 '^ ' 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 concernant 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 multiple (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 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 comme au moins une fois regex  :la regex A précédente correspond un nombre arbitraire de fois 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 du caractère 'b' s'il existe, mais il n'existe pas 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, 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 modèles A .
  • Le quantificateur A+ correspond à au moins un modèle 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 par 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.


Prochain article