Recherche…


Introduction

Python rend les expressions régulières disponibles via le module re .

Les expressions régulières sont des combinaisons de caractères interprétées comme des règles pour faire correspondre les sous-chaînes. Par exemple, l'expression 'amount\D+\d+' correspondra à toute chaîne composée du amount du mot plus un nombre entier, séparés par un ou plusieurs non-chiffres, tels que: amount=100 , amount is 3 , amount is equal to: 33 , etc.

Syntaxe

  • Expressions régulières directes

  • re.match (pattern, string, flag = 0) # Out: correspond à un motif au début de la chaîne ou à None

  • re.search (pattern, string, flag = 0) # Out: correspond à un motif à l'intérieur d'une chaîne ou à aucun

  • re.findall (pattern, string, flag = 0) # Out: liste de toutes les correspondances de pattern dans string ou []

  • re.finditer (pattern, string, flag = 0) # Out: identique à re.findall, mais retourne un objet d'itérateur

  • re.sub (pattern, replacement, string, flag = 0) # Out: chaîne avec remplacement (chaîne ou fonction) à la place du modèle

  • Expressions régulières précompilées

  • precompiled_pattern = re.compile (pattern, flag = 0)

  • precompiled_pattern.match (string) # Out: correspond au début de la chaîne ou None

  • precompiled_pattern.search (string) # Out: correspond à la chaîne ou à None

  • precompiled_pattern.findall (string) # Out: liste de toutes les sous-chaînes correspondantes

  • precompiled_pattern.sub (chaîne / modèle / fonction, chaîne) # Out: chaîne remplacée

Faire correspondre le début d'une chaîne

Le premier argument de re.match() est l'expression régulière, la seconde est la chaîne à rechercher:

import re

pattern = r"123"
string = "123zzb"

re.match(pattern, string)
# Out: <_sre.SRE_Match object; span=(0, 3), match='123'>

match = re.match(pattern, string)

match.group()
# Out: '123'

Vous remarquerez peut-être que la variable de modèle est une chaîne avec le préfixe r , qui indique que la chaîne est un littéral de chaîne brut .

Une chaîne brute littérale a une syntaxe légèrement différente de celle d' une chaîne littérale, à savoir une barre oblique inverse \ dans un moyen littéral de chaîne brute « juste une barre oblique inverse » et il n'y a pas besoin de doubler contrecoups pour échapper à « échapper à des séquences » telles que les nouvelles lignes ( \n ) , onglets ( \t ), backspaces ( \ ), flux de formulaire ( \r ), etc. Dans les littéraux de chaîne normaux, chaque barre oblique inverse doit être doublée pour éviter d'être considérée comme le début d'une séquence d'échappement.

Par conséquent, r"\n" est une chaîne de 2 caractères: \ et n . Les modèles d'expressions rationnelles utilisent également des barres obliques inverses, par exemple \d fait référence à n'importe quel caractère numérique. Nous pouvons éviter de devoir échapper à nos chaînes ( "\\d" ) en utilisant des chaînes brutes ( r"\d" ).

Par exemple:

string = "\\t123zzb" # here the backslash is escaped, so there's no tab, just '\' and 't'
pattern = "\\t123"   # this will match \t (escaping the backslash) followed by 123
re.match(pattern, string).group()   # no match
re.match(pattern, "\t123zzb").group()  # matches '\t123'

pattern = r"\\t123"  
re.match(pattern, string).group()   # matches '\\t123'

La correspondance est faite depuis le début de la chaîne uniquement. Si vous souhaitez faire correspondre n'importe où, utilisez plutôt re.search :

match = re.match(r"(123)", "a123zzb")

match is None
# Out: True

match = re.search(r"(123)", "a123zzb")

match.group()
# Out: '123'

Recherche

pattern = r"(your base)"
sentence = "All your base are belong to us."

match = re.search(pattern, sentence)
match.group(1)
# Out: 'your base'

match = re.search(r"(belong.*)", sentence)
match.group(1)
# Out: 'belong to us.'

La recherche se fait n'importe où dans la chaîne, contrairement à re.match . Vous pouvez également utiliser re.findall .

Vous pouvez également rechercher au début de la chaîne (utilisez ^ ),

match = re.search(r"^123", "123zzb")
match.group(0)
# Out: '123'

match = re.search(r"^123", "a123zzb")
match is None
# Out: True

à la fin de la chaîne (utilisez $ ),

match = re.search(r"123$", "zzb123")
match.group(0)
# Out: '123'

match = re.search(r"123$", "123zzb")
match is None
# Out: True

ou les deux (utilisez les deux ^ et $ ):

match = re.search(r"^123$", "123")
match.group(0)
# Out: '123'

Regroupement

Le regroupement se fait entre parenthèses. Le group() appelant group() renvoie une chaîne formée des sous-groupes entre parenthèses correspondants.

match.group() # Group without argument returns the entire match found
# Out: '123'
match.group(0) # Specifying 0 gives the same result as specifying no argument
# Out: '123'

Des arguments peuvent également être fournis à group() pour récupérer un sous-groupe particulier.

De la documentation :

S'il y a un seul argument, le résultat est une chaîne unique; s'il y a plusieurs arguments, le résultat est un tuple avec un élément par argument.

L'appel des groups() en revanche, renvoie une liste de tuples contenant les sous-groupes.

sentence = "This is a phone number 672-123-456-9910"
pattern = r".*(phone).*?([\d-]+)"

match = re.match(pattern, sentence)

match.groups()   # The entire match as a list of tuples of the paranthesized subgroups
# Out: ('phone', '672-123-456-9910')

m.group()        # The entire match as a string
# Out: 'This is a phone number 672-123-456-9910'

m.group(0)       # The entire match as a string
# Out: 'This is a phone number 672-123-456-9910'

m.group(1)       # The first parenthesized subgroup.
# Out: 'phone'

m.group(2)       # The second parenthesized subgroup.
# Out: '672-123-456-9910'

m.group(1, 2)    # Multiple arguments give us a tuple.
# Out: ('phone', '672-123-456-9910')

Groupes nommés

match = re.search(r'My name is (?P<name>[A-Za-z ]+)', 'My name is John Smith')
match.group('name')
# Out: 'John Smith'

match.group(1)
# Out: 'John Smith'

Crée un groupe de capture pouvant être référencé par nom et par index.

Groupes non capturés

L'utilisation de (?:) crée un groupe, mais le groupe n'est pas capturé. Cela signifie que vous pouvez l'utiliser en tant que groupe, mais cela ne polluera pas votre "espace de groupe".

re.match(r'(\d+)(\+(\d+))?', '11+22').groups()
# Out: ('11', '+22', '22')

re.match(r'(\d+)(?:\+(\d+))?', '11+22').groups()
# Out: ('11', '22')

Cet exemple correspond à 11+22 ou 11 , mais pas à 11+ . C'est depuis que le signe + et le second terme sont regroupés. Par contre, le signe + n'est pas capturé.

Échapper aux caractères spéciaux

Les caractères spéciaux (comme les accolades [ et ] ci-dessous) ne correspondent pas littéralement:

match = re.search(r'[b]', 'a[b]c')
match.group()
# Out: 'b'

En échappant aux caractères spéciaux, ils peuvent littéralement correspondre:

match = re.search(r'\[b\]', 'a[b]c')
match.group()
# Out: '[b]'

La fonction re.escape() peut être utilisée pour cela:

re.escape('a[b]c')
# Out: 'a\\[b\\]c'
match = re.search(re.escape('a[b]c'), 'a[b]c')
match.group()
# Out: 'a[b]c'

La fonction re.escape() échappe à tous les caractères spéciaux, il est donc utile que vous composiez une expression régulière en fonction de la saisie de l'utilisateur:

username = 'A.C.'  # suppose this came from the user
re.findall(r'Hi {}!'.format(username), 'Hi A.C.! Hi ABCD!')
# Out: ['Hi A.C.!', 'Hi ABCD!']
re.findall(r'Hi {}!'.format(re.escape(username)), 'Hi A.C.! Hi ABCD!')
# Out: ['Hi A.C.!']

Remplacer

Des remplacements peuvent être effectués sur des chaînes utilisant re.sub .

Remplacement des chaînes

re.sub(r"t[0-9][0-9]", "foo", "my name t13 is t44 what t99 ever t44")
# Out: 'my name foo is foo what foo ever foo'

Utiliser des références de groupe

Les remplacements avec un petit nombre de groupes peuvent être faits comme suit:

re.sub(r"t([0-9])([0-9])", r"t\2\1", "t13 t19 t81 t25")
# Out: 't31 t91 t18 t52'

Cependant, si vous créez un identifiant de groupe tel que "10", cela ne fonctionne pas : \10 est lu comme "ID numéro 1 suivi de 0". Il faut donc être plus précis et utiliser la notation \g<i> :

re.sub(r"t([0-9])([0-9])", r"t\g<2>\g<1>", "t13 t19 t81 t25")
# Out: 't31 t91 t18 t52'

Utiliser une fonction de remplacement

items = ["zero", "one", "two"]
re.sub(r"a\[([0-3])\]", lambda match: items[int(match.group(1))], "Items: a[0], a[1], something, a[2]")
# Out: 'Items: zero, one, something, two'

Trouver tous les matchs qui ne se chevauchent pas

re.findall(r"[0-9]{2,3}", "some 1 text 12 is 945 here 4445588899")
# Out: ['12', '945', '444', '558', '889']

Notez que le r avant "[0-9]{2,3}" indique à python d'interpréter la chaîne telle quelle; comme une chaîne "brute".

Vous pouvez également utiliser re.finditer() qui fonctionne de la même manière que re.findall() mais renvoie un itérateur avec des objets SRE_Match au lieu d'une liste de chaînes:

results = re.finditer(r"([0-9]{2,3})", "some 1 text 12 is 945 here 4445588899")
print(results)
# Out: <callable-iterator object at 0x105245890>
for result in results:
     print(result.group(0))
''' Out:
12
945
444
558
889
'''

Motifs précompilés

import re

precompiled_pattern = re.compile(r"(\d+)")
matches = precompiled_pattern.search("The answer is 41!")
matches.group(1)
# Out: 41

matches = precompiled_pattern.search("Or was it 42?")
matches.group(1)
# Out: 42

Compiler un modèle permet de le réutiliser ultérieurement dans un programme. Cependant, notez que Python met en cache les expressions récemment utilisées ( docs , réponse SO ), donc "les programmes qui n’utilisent que quelques expressions régulières à la fois n’ont pas à se soucier de la compilation des expressions régulières" .

import re

precompiled_pattern = re.compile(r"(.*\d+)")
matches = precompiled_pattern.match("The answer is 41!")
print(matches.group(1))
# Out: The answer is 41

matches = precompiled_pattern.match("Or was it 42?")
print(matches.group(1))
# Out: Or was it 42

Il peut être utilisé avec re.match ().

Vérification des caractères autorisés

Si vous voulez vérifier qu'une chaîne ne contient qu'un certain ensemble de caractères, dans ce cas az, AZ et 0-9, vous pouvez le faire comme ceci,

import re

def is_allowed(string):
    characherRegex = re.compile(r'[^a-zA-Z0-9.]')
    string = characherRegex.search(string)
    return not bool(string)
    
print (is_allowed("abyzABYZ0099")) 
# Out: 'True'

print (is_allowed("#*@#$%^")) 
# Out: 'False'

Vous pouvez également adapter la ligne d'expression de [^a-zA-Z0-9.] [^a-z0-9.] , Pour interdire par exemple les lettres majuscules.

Crédit partiel: http://stackoverflow.com/a/1325265/2697955

Fractionnement d'une chaîne à l'aide d'expressions régulières

Vous pouvez également utiliser des expressions régulières pour diviser une chaîne. Par exemple,

import re
data = re.split(r'\s+', 'James 94 Samantha 417 Scarlett 74')
print( data )
# Output: ['James', '94', 'Samantha', '417', 'Scarlett', '74']

Les drapeaux

Pour certains cas particuliers, nous devons modifier le comportement de l’expression régulière, en utilisant les indicateurs. Les flags peuvent être définis de deux manières, via le mot-clé flags ou directement dans l'expression.

Mot-clé Drapeaux

Ci-dessous un exemple pour re.search mais cela fonctionne pour la plupart des fonctions du module re .

m = re.search("b", "ABC")  
m is None
# Out: True

m = re.search("b", "ABC", flags=re.IGNORECASE)
m.group()
# Out: 'B'

m = re.search("a.b", "A\nBC", flags=re.IGNORECASE) 
m is None
# Out: True

m = re.search("a.b", "A\nBC", flags=re.IGNORECASE|re.DOTALL) 
m.group()
# Out: 'A\nB'

Drapeaux communs

Drapeau brève description
re.IGNORECASE , re.I Fait le motif ignorer le cas
re.DOTALL , re.S Fait . correspondre à tout, y compris les nouvelles lignes
re.MULTILINE , re.M Donne ^ correspond au début d'une ligne et $ la fin d'une ligne
re.DEBUG Active les informations de débogage

Pour la liste complète de tous les drapeaux disponibles, vérifiez les documents

Drapeaux en ligne

De la documentation :

(?iLmsux) (Une ou plusieurs lettres de l'ensemble 'i', 'L', 'm', 's', 'u', 'x'.)

Le groupe correspond à la chaîne vide; les lettres définissent les drapeaux correspondants: re.I (ignore case), re.L (dépendant de la locale), re.M (multi-line), re.S (dot match all), re.U (dépendant d'Unicode), et re.X (verbose), pour toute l'expression régulière. Ceci est utile si vous souhaitez inclure les drapeaux dans l'expression régulière, au lieu de transmettre un argument flag à la fonction re.compile ().

Notez que l'indicateur (? X) modifie la façon dont l'expression est analysée. Il doit être utilisé en premier dans la chaîne d'expression, ou après un ou plusieurs caractères d'espacement. S'il y a des caractères non blancs avant le drapeau, les résultats ne sont pas définis.

Itérer sur les correspondances en utilisant `re.finditer`

Vous pouvez utiliser re.finditer pour parcourir tous les résultats d'une chaîne. Cela vous donne (en comparaison avec re.findall des informations supplémentaires, telles que des informations sur l'emplacement de la correspondance dans la chaîne (index):

import re
text = 'You can try to find an ant in this string'
pattern = 'an?\w' # find 'an' either with or without a following word character

for match in re.finditer(pattern, text):
    # Start index of match (integer)
    sStart = match.start()

    # Final index of match (integer)
    sEnd = match.end()

    # Complete match (string)
    sGroup = match.group()

    # Print match
    print('Match "{}" found at: [{},{}]'.format(sGroup, sStart,sEnd))

Résultat:

Match "an" found at: [5,7]
Match "an" found at: [20,22]
Match "ant" found at: [23,26]

Correspond à une expression uniquement dans des emplacements spécifiques

Souvent, vous souhaitez faire correspondre une expression uniquement à des endroits spécifiques (les laissant intacts dans d’autres, c’est-à-dire). Considérons la phrase suivante:

An apple a day keeps the doctor away (I eat an apple everyday).

Ici, la "pomme" se produit deux fois, ce qui peut être résolu avec des verbes de contrôle appelés " backtracking" qui sont supportés par le nouveau module regex . L'idée est la suivante:

forget_this | or this | and this as well | (but keep this)

Avec notre exemple Apple, ce serait:

import regex as re
string = "An apple a day keeps the doctor away (I eat an apple everyday)."
rx = re.compile(r'''
    \([^()]*\) (*SKIP)(*FAIL)  # match anything in parentheses and "throw it away"
    |                          # or
    apple                      # match an apple
    ''', re.VERBOSE)
apples = rx.findall(string)
print(apples)
# only one

Ceci ne correspond à "apple" que s'il peut être trouvé en dehors des parenthèses.


Voici comment cela fonctionne:
  • En regardant de gauche à droite , le moteur regex consomme tout à gauche, le (*SKIP) agit comme une "assertion toujours vraie". Ensuite, il échoue correctement (*FAIL) et les backtracks.
  • Maintenant, il arrive au point de (*SKIP) de droite à gauche (alias en revenant en arrière) où il est interdit d'aller plus loin vers la gauche. Au lieu de cela, on dit au moteur de jeter tout ce qui est à gauche et de sauter au point où le (*SKIP) été invoqué.


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow