Comment utiliser une variable à l'intérieur d'une expression régulière?


235

Je voudrais utiliser un variableintérieur regex, comment puis-je le faire Python?

TEXTO = sys.argv[1]

if re.search(r"\b(?=\w)TEXTO\b(?!\w)", subject, re.IGNORECASE):
    # Successful match
else:
    # Match attempt failed

9
Vous utilisez la concaténation de chaînes
Chris Eberle

Réponses:


52

A partir de python 3.6, vous pouvez également utiliser l' interpolation de chaînes littérales , "f-strings". Dans votre cas particulier, la solution serait:

if re.search(rf"\b(?=\w){TEXTO}\b(?!\w)", subject, re.IGNORECASE):
    ...do something

ÉDITER:

Puisqu'il y a eu quelques questions dans le commentaire sur la façon de traiter les caractères spéciaux, j'aimerais étendre ma réponse:

chaînes brutes («r»):

L'un des principaux concepts que vous devez comprendre lorsque vous traitez avec des caractères spéciaux dans les expressions régulières est de faire la distinction entre les littéraux de chaîne et l'expression régulière elle-même. C'est très bien expliqué ici :

En bref:

Disons qu'au lieu de trouver une limite de mot \baprès avoir TEXTOvoulu faire correspondre la chaîne \boundary. Le vous devez écrire:

TEXTO = "Var"
subject = r"Var\boundary"

if re.search(rf"\b(?=\w){TEXTO}\\boundary(?!\w)", subject, re.IGNORECASE):
    print("match")

Cela ne fonctionne que parce que nous utilisons une chaîne brute (l'expression régulière est précédée de 'r'), sinon nous devons écrire "\\\\ limite" dans l'expression régulière (quatre barres obliques inverses). De plus, sans '\ r', \ b 'ne serait plus converti en frontière de mot mais en retour arrière!

re.escape :

Met essentiellement un retour arrière devant tout caractère spécial. Par conséquent, si vous attendez un caractère spécial dans TEXTO, vous devez écrire:

if re.search(rf"\b(?=\w){re.escape(TEXTO)}\b(?!\w)", subject, re.IGNORECASE):
    print("match")

REMARQUE: Pour toute version> = python 3.7: !, ", %, ', ,, /, :, ;, <, =, >, @et `ne sont pas échappés. Seuls les caractères spéciaux ayant une signification dans une expression régulière sont toujours échappés. _n'est pas échappé depuis Python 3.3. (s. ici )

Accolades:

Si vous souhaitez utiliser des quantificateurs dans l'expression régulière à l'aide de chaînes f, vous devez utiliser des accolades doubles. Supposons que vous souhaitiez faire correspondre TEXTO suivi d'exactement 2 chiffres:

if re.search(rf"\b(?=\w){re.escape(TEXTO)}\d{{2}}\b(?!\w)", subject, re.IGNORECASE):
    print("match")

2
À partir de 2020, c'est la manière la plus simple et la plus pythonique d'utiliser une variable à l'intérieur d'une expression régulière
CONvid19

3
C'est définitivement un WOW .
Jason Goal

2
quelqu'un peut-il expliquer la signification de "rf" ici
Harsha Reddy

1
@HarshaReddy: 'r': Cette chaîne est une chaîne brute: si vous ne l'utilisez pas, '\ b' sera converti en caractère de retour arrière ( docs.python.org/3/howto/regex.html#more- modèle-puissance ). 'f' indique à python qu'il s'agit d'une 'f-chaîne', s. lien ci-dessus, et vous permet d'écrire la variable dans les accolades
aéroporté le

2
Comment écrire des quantificateurs dans les chaînes f: fr"foo{{1,5}}"(double les accolades)
PunchyRascal

281

Vous devez construire l'expression régulière sous forme de chaîne:

TEXTO = sys.argv[1]
my_regex = r"\b(?=\w)" + re.escape(TEXTO) + r"\b(?!\w)"

if re.search(my_regex, subject, re.IGNORECASE):
    etc.

Notez l'utilisation de re.escapeafin que si votre texte comporte des caractères spéciaux, ils ne seront pas interprétés comme tels.


4
Et si votre variable passe en premier? r'' + foo + 'bar'?
deed02392

@ deed02392 r''pas nécessaire si vous le faites re.escape(foo), ce que vous devriez de toute façon. En fait, je pense reque tout ce qui est donné est interprété comme une chaîne unicode, que vous préfériez rou non.
OJFord

Est-ce que .format () fonctionne aussi bien à la place de re.escape ou est-ce que re.escape () est nécessaire?
Praxiteles

@praxiteles avez-vous trouvé la réponse?
CONvid19

2
Je ne sais pas si cela fonctionne, j'ai besoin d'un groupe dont la variable fait partie. Les autres réponses ci-dessous semblent plus intuitives pour cela, et ne divisent pas l'expression régulière en plusieurs expressions.
guival

48
if re.search(r"\b(?<=\w)%s\b(?!\w)" % TEXTO, subject, re.IGNORECASE):

Cela insérera ce qui est dans TEXTO dans l'expression régulière sous forme de chaîne.



6

Je trouve très pratique de créer un modèle d'expression régulière en enchaînant plusieurs modèles plus petits.

import re

string = "begin:id1:tag:middl:id2:tag:id3:end"
re_str1 = r'(?<=(\S{5})):'
re_str2 = r'(id\d+):(?=tag:)'
re_pattern = re.compile(re_str1 + re_str2)
match = re_pattern.findall(string)
print(match)

Production:

[('begin', 'id1'), ('middl', 'id2')]

4

Je suis d'accord avec tout ce qui précède à moins que:

sys.argv[1] était quelque chose comme Chicken\d{2}-\d{2}An\s*important\s*anchor

sys.argv[1] = "Chicken\d{2}-\d{2}An\s*important\s*anchor"

vous ne voudriez pas utiliser re.escape, car dans ce cas, vous aimeriez qu'il se comporte comme une expression régulière

TEXTO = sys.argv[1]

if re.search(r"\b(?<=\w)" + TEXTO + "\b(?!\w)", subject, re.IGNORECASE):
    # Successful match
else:
    # Match attempt failed

2

J'avais besoin de rechercher des noms d'utilisateur similaires les uns aux autres, et ce que Ned Batchelder a dit était incroyablement utile. Cependant, j'ai trouvé que j'avais une sortie plus propre lorsque j'ai utilisé re.compile pour créer mon terme de recherche:

pattern = re.compile(r"("+username+".*):(.*?):(.*?):(.*?):(.*)"
matches = re.findall(pattern, lines)

La sortie peut être imprimée à l'aide des éléments suivants:

print(matches[1]) # prints one whole matching line (in this case, the first line)
print(matches[1][3]) # prints the fourth character group (established with the parentheses in the regex statement) of the first line.

1

vous pouvez essayer une autre utilisation en utilisant formatgrammer suger:

re_genre = r'{}'.format(your_variable)
regex_pattern = re.compile(re_genre)  

0

Vous pouvez également utiliser le mot-clé format pour cela. La méthode format remplacera l'espace réservé {} à la variable que vous avez passée à la méthode format comme argument.

if re.search(r"\b(?=\w)**{}**\b(?!\w)".**format(TEXTO)**, subject, re.IGNORECASE):
    # Successful match**strong text**
else:
    # Match attempt failed

0

plus d'exemple

J'ai configus.yml avec des fichiers de flux

"pattern":
  - _(\d{14})_
"datetime_string":
  - "%m%d%Y%H%M%f"

dans le code python que j'utilise

data_time_real_file=re.findall(r""+flows[flow]["pattern"][0]+"", latest_file)
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.