Como usar uma variável dentro de uma expressão regular?

235

Eu gostaria de usar um variabledentro de regex, como posso fazer isso Python?

TEXTO = sys.argv[1]

if re.search(r"\b(?=\w)TEXTO\b(?!\w)", subject, re.IGNORECASE):
    # Successful match
else:
    # Match attempt failed
CONvid19
fonte
9
Você usa concatenação de strings
Chris Eberle

Respostas:

52

Do python 3.6 em diante, você também pode usar a Interpolação de String Literal , "f-strings". No seu caso particular, a solução seria:

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

EDITAR:

Como houve algumas perguntas no comentário sobre como lidar com caracteres especiais, gostaria de estender minha resposta:

strings brutos ('r'):

Um dos principais conceitos que você precisa entender ao lidar com caracteres especiais em expressões regulares é distinguir entre literais de string e a própria expressão regular. É muito bem explicado aqui :

Em resumo:

Digamos, em vez de encontrar um limite de palavra \bdepois que TEXTOvocê deseja corresponder à string \boundary. O que você tem que escrever:

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

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

Isso funciona apenas porque estamos usando uma string não processada (o regex é precedido por 'r'); caso contrário, devemos escrever "\\\\ limite" no regex (quatro barras invertidas). Além disso, sem '\ r', \ b 'não seria mais convertido em um limite de palavras, mas em um backspace!

re.escape :

Basicamente, coloca um backspace na frente de qualquer caractere especial. Portanto, se você espera um caractere especial em TEXTO, precisa escrever:

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

NOTA: Para qualquer versão> = python 3.7: !, ", %, ', ,, /, :, ;, <, =, >, @, e `não são escapou. Somente caracteres especiais com significado em uma regex ainda são escapados. _não é escapado desde o Python 3.3. (s. aqui )

Aparelhos encaracolados:

Se você deseja usar quantificadores dentro da expressão regular usando seqüências de f, precisará usar chaves duplas. Digamos que você queira corresponder ao TEXTO seguido por exatamente 2 dígitos:

if re.search(rf"\b(?=\w){re.escape(TEXTO)}\d{{2}}\b(?!\w)", subject, re.IGNORECASE):
    print("match")
transportado pelo ar
fonte
2
A partir de 2020, esta é a maneira mais simples e mais pitônica de usar uma variável dentro de uma expressão regular
CONvid19 de
3
Este é definitivamente um WOW .
Jason Goal
2
alguém pode explicar o significado de "rf" aqui
Harsha Reddy 25/02
1
@HarshaReddy: 'r': esta sequência é uma sequência bruta: se você não a usar, '\ b' será convertido no caractere backspace ( docs.python.org/3/howto/regex.html#more- poder-padrão ). 'f' diz ao python que este é um 'f-string', s. link acima e permite que você escreva a variável nos chavetas-
ar
2
Como escrever quantificadores em strings f: fr"foo{{1,5}}"(double the chaves)
PunchyRascal
281

Você precisa criar o regex como uma string:

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

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

Observe o uso de re.escapepara que, se o seu texto tiver caracteres especiais, eles não serão interpretados como tal.

Ned Batchelder
fonte
4
E se sua variável for a primeira? r'' + foo + 'bar'?
precisa
@ deed02392 r''não é necessário se você o fizer re.escape(foo), o que deve ser feito de qualquer maneira. Na verdade, acho que reinterpreta o que quer que seja dado como uma string unicode, independentemente de você prefixar rou não.
OJFord 13/08/14
.Format () também funciona no lugar do re.escape ou é necessário re.escape ()?
Praxiteles
@praxiteles você encontrou a resposta?
perfil completo de CONVID19
2
Não tenho certeza se isso funciona, preciso ter um grupo do qual a variável faça parte. Outras respostas abaixo parecem mais intuitivas para isso e não dividem a expressão regular em várias expressões.
guival
48
if re.search(r"\b(?<=\w)%s\b(?!\w)" % TEXTO, subject, re.IGNORECASE):

Isto irá inserir o que está no TEXTO no regex como uma string.

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

Acho muito conveniente criar um padrão de expressão regular unindo vários padrões menores.

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)

Resultado:

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

Eu concordo com todos os itens acima, 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"

você não gostaria de usar re.escape, porque nesse caso você gostaria que ele se comportasse como uma regex

TEXTO = sys.argv[1]

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

Eu precisava procurar nomes de usuários semelhantes entre si, e o que Ned Batchelder disse foi incrivelmente útil. No entanto, descobri que tinha uma saída mais limpa quando usei re.compile para criar meu termo de pesquisa:

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

A saída pode ser impressa usando o seguinte:

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

você pode tentar outro uso usando a formatgrammer suger:

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

Você também pode usar a palavra-chave format para isso. O método Form substitui o espaço reservado {} pela variável que você passou para o método format 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
fonte
0

mais exemplo

Eu tenho configus.yml com arquivos de fluxos

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

no código python eu uso

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