¿Cómo usar una variable dentro de una expresión regular?

235

Me gustaría usar un variableinside a regex, ¿cómo puedo hacer esto Python?

TEXTO = sys.argv[1]

if re.search(r"\b(?=\w)TEXTO\b(?!\w)", subject, re.IGNORECASE):
    # Successful match
else:
    # Match attempt failed
CONvid19
fuente
99
Utiliza la concatenación de cadenas
Chris Eberle

Respuestas:

52

A partir de python 3.6 también puede usar la interpolación de cadenas literales , "cadenas f". En su caso particular, la solución sería:

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

EDITAR:

Dado que ha habido algunas preguntas en el comentario sobre cómo tratar con caracteres especiales, me gustaría extender mi respuesta:

cadenas sin formato ('r'):

Uno de los conceptos principales que debe comprender al tratar con caracteres especiales en expresiones regulares es distinguir entre literales de cadena y la propia expresión regular. Aquí está muy bien explicado :

En breve:

Digamos en lugar de encontrar un límite de palabra \bdespués de TEXTOque desee hacer coincidir la cadena \boundary. El tienes que escribir:

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

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

Esto solo funciona porque estamos usando una cadena sin formato (la expresión regular va precedida por 'r'), de lo contrario debemos escribir "\\\\ boundary" en la expresión regular (cuatro barras diagonales inversas). ¡Además, sin '\ r', \ b 'ya no se convertiría en un límite de palabra sino en un retroceso!

re.escape :

Básicamente pone un retroceso delante de cualquier personaje especial. Por lo tanto, si espera un carácter especial en TEXTO, debe escribir:

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

NOTA: Para cualquier versión> = 3.7 pitón: !, ", %, ', ,, /, :, ;, <, =, >, @, y `no se escapan. Solo se escapan los caracteres especiales con significado en una expresión regular. _no se escapa desde Python 3.3. (s. aquí )

Llaves:

Si desea usar cuantificadores dentro de la expresión regular usando cadenas f, debe usar llaves dobles. Digamos que desea hacer coincidir TEXTO seguido de exactamente 2 dígitos:

if re.search(rf"\b(?=\w){re.escape(TEXTO)}\d{{2}}\b(?!\w)", subject, re.IGNORECASE):
    print("match")
aerotransportado
fuente
2
A partir de 2020, esta es la forma más simple y más pitónica de usar una variable dentro de una expresión regular
CONvid19
3
Esto es definitivamente un WOW .
Jason Goal
2
alguien puede explicar el significado de "rf" aquí
Harsha Reddy
1
@HarshaReddy: 'r': esta cadena es una cadena sin procesar: si no la usa, '\ b' se convertirá en el carácter de retroceso ( docs.python.org/3/howto/regex.html#more- patrón de potencia ). 'f' le dice a python que este es un 'f-string', s. enlace anterior, y le permite escribir la variable en llaves
aire
2
Cómo escribir cuantificadores en cadenas f: fr"foo{{1,5}}"(doblar las llaves)
PunchyRascal
281

Tienes que construir la expresión regular como una cadena:

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

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

Tenga en cuenta el uso de re.escapemodo que si su texto tiene caracteres especiales, no se interpretarán como tales.

Ned Batchelder
fuente
44
¿Qué pasa si su variable va primero? r'' + foo + 'bar'?
deed02392
@ deed02392 r''no es necesario si lo hace re.escape(foo), lo cual debería de todos modos. En realidad, creo que reinterpreta lo que se le da como una cadena Unicode, independientemente de si prefieres ro no.
OJFord
¿Funciona .format () en lugar del re.escape o es necesario re.escape ()?
Praxiteles
@praxiteles ¿encontraste la respuesta?
CONvid19
2
No estoy seguro de si esto funciona, necesito tener un grupo del que forme parte la variable. Otras respuestas a continuación parecen más intuitivas para eso, y no dividen la expresión regular en varias expresiones.
Guival
48
if re.search(r"\b(?<=\w)%s\b(?!\w)" % TEXTO, subject, re.IGNORECASE):

Esto insertará lo que está en TEXTO en la expresión regular como una cadena.

Bo Buchanan
fuente
37
rx = r'\b(?<=\w){0}\b(?!\w)'.format(TEXTO)
Cat Plus Plus
fuente
6

Me parece muy conveniente construir un patrón de expresión regular al unir múltiples patrones más pequeños.

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)

Salida:

[('begin', 'id1'), ('middl', 'id2')]
Deepak Nagarajan
fuente
4

Estoy de acuerdo con todo lo anterior a menos que:

sys.argv[1] era algo como Chicken\d{2}-\d{2}An\s*important\s*anchor

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

no querrá usar re.escape, porque en ese caso le gustaría que se comportara como una expresión regular

TEXTO = sys.argv[1]

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

Necesitaba buscar nombres de usuario similares entre sí, y lo que dijo Ned Batchelder fue increíblemente útil. Sin embargo, descubrí que tenía una salida más limpia cuando usé re.compile para crear mi término de búsqueda:

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

La salida se puede imprimir usando lo siguiente:

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
fuente
1

puedes probar otro uso usando formatgrammer suger:

re_genre = r'{}'.format(your_variable)
regex_pattern = re.compile(re_genre)  
Kevin Chou
fuente
0

También puede usar la palabra clave de formato para esto. El método de formato reemplazará {} marcador de posición a la variable que pasó al método de formato como argumento.

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

mas ejemplo

Tengo configus.yml con archivos de flujos

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

en el código de Python que uso

data_time_real_file=re.findall(r""+flows[flow]["pattern"][0]+"", latest_file)
Nikolay Baranenko
fuente