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
CONvid19
la source
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")
aéroporté
la source
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.

Ned Batchelder
la source
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.

Bo Buchanan
la source
37
rx = r'\b(?<=\w){0}\b(?!\w)'.format(TEXTO)
Cat Plus Plus
la source
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')]
Deepak Nagarajan
la source
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
Max Carroll
la source
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.
jdelaporte
la source
1

vous pouvez essayer une autre utilisation en utilisant formatgrammer suger:

re_genre = r'{}'.format(your_variable)
regex_pattern = re.compile(re_genre)  
Kevin Chou
la source
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
Haneef Mohammed
la source
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)
Nikolay Baranenko
la source