Como utilizar o módulo de expressão regular Python re (correspondência, pesquisa, sub, etc.)

O negócio

Para realizar o processamento regular da expressão em Python, utilizamos o módulo re da biblioteca padrão. Ele permite extrair, substituir, e dividir cordas usando padrões de expressão regular.

Nesta secção, vamos primeiro explicar as funções e métodos do módulo re.

  • Compilação de padrões de expressão regular:compile()
  • objecto correspondente
  • Verificar se o início da corda corresponde, extrair:match()
  • Verificar a existência de fósforos não limitados ao início:search()
  • Verificar se a corda inteira corresponde:fullmatch()
  • Obter uma lista de todas as peças correspondentes:findall()
  • Obtenha todas as peças correspondentes como um iterador:finditer()
  • Substituir a peça correspondente:sub(),subn()
  • Dividir as cordas com padrões de expressão regulares:split()

Depois disso, explicarei os meta caracteres (caracteres especiais) e as sequências especiais de expressões regulares que podem ser utilizadas no módulo de re. Basicamente, é a sintaxe padrão das expressões regulares, mas tenha cuidado ao colocar bandeiras (especialmente re.ASCII).

  • Metacaracteres de expressão regular, sequências especiais, e advertências em Python
  • Pôr a bandeira
    • Limitado a caracteres ASCII:re.ASCII
    • Não sensível a maiúsculas e minúsculas:re.IGNORECASE
    • Combinar o início e o fim de cada linha:re.MULTILINE
    • Especificar bandeiras múltiplas
  • Jogos gananciosos e não gananciosos

Compilar o padrão de expressão regular: compilar()

Há duas maneiras de executar o processamento regular da expressão no módulo re.

Executar com função

A primeira é uma função.re.match(),re.sub()Funções como estas estão disponíveis para realizar extracção, substituição, e outros processos que utilizam padrões de expressão regulares.

Os detalhes das funções serão descritos mais tarde, mas em todas elas, o primeiro argumento é o fio do padrão de expressão regular, seguido do fio a ser processado e assim por diante. Por exemplo, no re.sub(), que executa a substituição, o segundo argumento é a cadeia de substituição, e o terceiro argumento é a cadeia a ser processada.

import re

s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'

m = re.match(r'([a-z]+)@([a-z]+)\.com', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

result = re.sub(r'([a-z]+)@([a-z]+)\.com', 'new-address', s)
print(result)
# new-address, new-address, ccc@zzz.net

Note-se que [a-z] no padrão de expressão regular neste exemplo significa qualquer caractere de a a a z (ou seja, alfabeto minúsculo), e + significa repetir o padrão anterior (neste caso [a-z]) uma ou mais vezes. O [a-z]+ corresponde a qualquer cadeia que repete um ou mais caracteres alfabéticos em minúsculas.

. é uma meta personagem (um personagem com significado especial) e deve ser escapado com uma contrabarra.

Uma vez que as cordas com padrão de expressão regular usam frequentemente muitas barras invertidas, é conveniente usar cordas em bruto como no exemplo.

Funciona com um método de um objecto de padrão de expressão regular

A segunda forma de processar expressões regulares no módulo re é o método do objecto padrão de expressão regular.

Usando re.compile(), é possível compilar uma cadeia padrão de expressão regular para criar um objecto padrão de expressão regular.

p = re.compile(r'([a-z]+)@([a-z]+)\.com')

print(p)
# re.compile('([a-z]+)@([a-z]+)\\.com')

print(type(p))
# <class 're.Pattern'>

re.match(),re.sub()Por exemplo, o mesmo processo que estas funções podem ser executadas como métodos de correspondência(),sub() de objectos de expressão regular.

m = p.match(s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

result = p.sub('new-address', s)
print(result)
# new-address, new-address, ccc@zzz.net

Todas as funções re.xxx() descritas abaixo são também fornecidas como métodos do objecto de expressão regular.

Se estiver a repetir um processo que utiliza o mesmo padrão, é mais eficiente gerar um objecto de expressão regular com re.compile() e utilizá-lo em redor.

No seguinte código de amostra, a função é utilizada sem compilação por conveniência, mas se quiser utilizar o mesmo padrão repetidamente, recomenda-se compilá-lo antecipadamente e executá-lo como um método de um objecto de expressão regular.

objecto correspondente

match(), search(), etc. devolver um objecto correspondente.

s = 'aaa@xxx.com'

m = re.match(r'[a-z]+@[a-z]+\.[a-z]+', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

print(type(m))
# <class 're.Match'>

O fio e a posição correspondentes são obtidos utilizando os seguintes métodos do objecto correspondente.

  • Obter a localização da partida:start(),end(),span()
  • Obter o cordel correspondente:group()
  • Obtenha o cordel para cada grupo:groups()
print(m.start())
# 0

print(m.end())
# 11

print(m.span())
# (0, 11)

print(m.group())
# aaa@xxx.com

Se incluir uma parte de um padrão de expressão regular num fio com parênteses(), a parte será processada como um grupo. Neste caso, a cadeia da parte que corresponde a cada grupo em grupos() pode ser obtida como um tuple.

m = re.match(r'([a-z]+)@([a-z]+)\.([a-z]+)', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

print(m.groups())
# ('aaa', 'xxx', 'com')

Verifique se o início de uma corda corresponde, extracto: corresponde()

match() devolve um objecto correspondente se o início da cadeia corresponder ao padrão.

Como mencionado acima, o objecto correspondente pode ser utilizado para extrair o substrato correspondente, ou simplesmente para verificar se foi feita uma correspondência.

match() só irá verificar o início. Se não houver correspondência no início, devolve Nenhuma.

s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'

m = re.match(r'[a-z]+@[a-z]+\.com', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

m = re.match(r'[a-z]+@[a-z]+\.net', s)
print(m)
# None

Verificar se há correspondências não limitadas ao início, extracto: pesquisa()

Tal como match(), devolve um objecto compatível se este corresponder.

Se houver várias peças correspondentes, apenas a primeira peça correspondente será devolvida.

s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'

m = re.search(r'[a-z]+@[a-z]+\.net', s)
print(m)
# <re.Match object; span=(26, 37), match='ccc@zzz.net'>

m = re.search(r'[a-z]+@[a-z]+\.com', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

Se quiser obter todas as peças correspondentes, use findall() ou finditer() como descrito abaixo.

Verificar se a corda inteira corresponde: fullmatch()

Para verificar se a corda inteira corresponde ao padrão de expressão regular, usar fullmatch(). Isto é útil, por exemplo, para verificar se uma cadeia de caracteres é válida como endereço de correio electrónico ou não.

Se a corda inteira corresponder, um objecto correspondente é devolvido.

s = 'aaa@xxx.com'

m = re.fullmatch(r'[a-z]+@[a-z]+\.com', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

Se houver peças inigualáveis (apenas partidas parciais ou nenhuma partida), nenhuma é devolvida.

s = '!!!aaa@xxx.com!!!'

m = re.fullmatch(r'[a-z]+@[a-z]+\.com', s)
print(m)
# None

O fullmatch() foi adicionado em Python 3.4. Se quiser fazer o mesmo nas versões anteriores, use match() e um meta caractere correspondente $ no final. Se a cadeia completa do início ao fim não corresponder, devolve Nenhum.

s = '!!!aaa@xxx.com!!!'

m = re.match(r'[a-z]+@[a-z]+\.com$', s)
print(m)
# None

Obtenha uma lista de todas as peças correspondentes: findall()

findall() devolve uma lista de todos os substratos correspondentes. Note-se que os elementos da lista não são objectos correspondentes, mas sim cordas.

s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'

result = re.findall(r'[a-z]+@[a-z]+\.[a-z]+', s)
print(result)
# ['aaa@xxx.com', 'bbb@yyy.com', 'ccc@zzz.net']

O número de peças combinadas pode ser verificado utilizando a função len() integrada, que devolve o número de elementos da lista.

print(len(result))
# 3

O agrupamento com parênteses() num padrão de expressão regular retorna uma lista de tuplos cujos elementos são as cordas de cada grupo. Isto é equivalente a grupos() no objecto correspondente.

result = re.findall(r'([a-z]+)@([a-z]+)\.([a-z]+)', s)
print(result)
# [('aaa', 'xxx', 'com'), ('bbb', 'yyy', 'com'), ('ccc', 'zzz', 'net')]

Os parênteses do grupo () podem ser aninhados, por isso, se também quiser obter a partida inteira, basta juntar a partida inteira entre parênteses ().

result = re.findall(r'(([a-z]+)@([a-z]+)\.([a-z]+))', s)
print(result)
# [('aaa@xxx.com', 'aaa', 'xxx', 'com'), ('bbb@yyy.com', 'bbb', 'yyy', 'com'), ('ccc@zzz.net', 'ccc', 'zzz', 'net')]

Se não for encontrado nenhum fósforo, é devolvido um tuple vazio.

result = re.findall('[0-9]+', s)
print(result)
# []

Obtenha todas as peças correspondentes como um iterador: finditer()

finditer() devolve todas as peças correspondentes como um iterador. Os elementos não são cordas como findall(), mas correspondem a objectos, para que se possa obter a posição (índice) das peças combinadas.

O iterador em si não pode ser impresso com impressão() para obter o seu conteúdo. Se utilizar a função integrada a seguir() ou a função para declaração, pode obter o conteúdo um a um.

s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'

result = re.finditer(r'[a-z]+@[a-z]+\.[a-z]+', s)
print(result)
# <callable_iterator object at 0x10b0efa90>

print(type(result))
# <class 'callable_iterator'>

for m in result:
    print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>
# <re.Match object; span=(13, 24), match='bbb@yyy.com'>
# <re.Match object; span=(26, 37), match='ccc@zzz.net'>

Também pode ser convertido para uma lista com lista().

l = list(re.finditer(r'[a-z]+@[a-z]+\.[a-z]+', s))
print(l)
# [<re.Match object; span=(0, 11), match='aaa@xxx.com'>, <re.Match object; span=(13, 24), match='bbb@yyy.com'>, <re.Match object; span=(26, 37), match='ccc@zzz.net'>]

print(l[0])
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

print(type(l[0]))
# <class 're.Match'>

print(l[0].span())
# (0, 11)

Se quiser obter a posição de todas as peças correspondentes, a notação de compreensão da lista é mais conveniente do que a lista().

print([m.span() for m in re.finditer(r'[a-z]+@[a-z]+\.[a-z]+', s)])
# [(0, 11), (13, 24), (26, 37)]

O iterador retira elementos em ordem. Note-se que se tentar extrair mais elementos depois de chegar ao fim, ficará sem nada.

result = re.finditer(r'[a-z]+@[a-z]+\.[a-z]+', s)

for m in result:
    print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>
# <re.Match object; span=(13, 24), match='bbb@yyy.com'>
# <re.Match object; span=(26, 37), match='ccc@zzz.net'>

print(list(result))
# []

Substituir as peças correspondentes: sub(), subn()

Usando sub(), pode substituir a peça correspondente por outra corda. A corda substituída será devolvida.

s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'

result = re.sub(r'[a-z]+@[a-z]+\.com', 'new-address', s)
print(result)
# new-address, new-address, ccc@zzz.net

print(type(result))
# <class 'str'>

Ao agrupar com parênteses(), a corda correspondente pode ser utilizada na corda substituída.

Por defeito, é suportado o seguinte: Note-se que para cordas normais que não são cordas em bruto, uma barra invertida deve ser listada antes da barra invertida para escapar à barra invertida.

\1O primeiro parêntese
\2O segundo parêntese
\3O terceiro parêntese
result = re.sub(r'([a-z]+)@([a-z]+)\.com', r'\1@\2.net', s)
print(result)
# aaa@xxx.net, bbb@yyy.net, ccc@zzz.net

?P<xxx>
Se nomear o grupo escrevendo isto no início dos parênteses do padrão de expressão regular, pode especificá-lo usando o nome em vez do número, como mostrado abaixo.
\g<xxx>

result = re.sub(r'(?P<local>[a-z]+)@(?P<SLD>[a-z]+)\.com', r'\g<local>@\g<SLD>.net', s)
print(result)
# aaa@xxx.net, bbb@yyy.net, ccc@zzz.net

A contagem dos argumentos especifica o número máximo de substituições. Apenas a contagem do lado esquerdo será substituída.

result = re.sub(r'[a-z]+@[a-z]+\.com', 'new-address', s, count=1)
print(result)
# new-address, bbb@yyy.com, ccc@zzz.net

subn() devolve um tuple da string substituída (igual ao valor de retorno de sub()) e o número de peças substituídas (o número que corresponde ao padrão).

result = re.subn(r'[a-z]+@[a-z]+\.com', 'new-address', s)
print(result)
# ('new-address, new-address, ccc@zzz.net', 2)

O método de especificar argumentos é o mesmo que sub(). Pode utilizar a parte agrupada por parênteses, ou especificar a contagem dos argumentos.

result = re.subn(r'(?P<local>[a-z]+)@(?P<SLD>[a-z]+)\.com', r'\g<local>@\g<SLD>.net', s)
print(result)
# ('aaa@xxx.net, bbb@yyy.net, ccc@zzz.net', 2)

result = re.subn(r'[a-z]+@[a-z]+\.com', 'new-address', s, count=1)
print(result)
# ('new-address, bbb@yyy.com, ccc@zzz.net', 1)

Dividir cordas com padrões de expressão regular: split()

split() divide a corda na parte que corresponde ao padrão, e devolve-a como uma lista.

Note-se que o primeiro e o último jogos conterão cordas vazias no início e no fim da lista resultante.

s = '111aaa222bbb333'

result = re.split('[a-z]+', s)
print(result)
# ['111', '222', '333']

result = re.split('[0-9]+', s)
print(result)
# ['', 'aaa', 'bbb', '']

O argumento da divisão máxima especifica o número máximo de divisões (peças). Apenas a contagem a partir do lado esquerdo será dividida.

result = re.split('[a-z]+', s, 1)
print(result)
# ['111', '222bbb333']

Metacaracteres de expressão regular, sequências especiais, e advertências em Python

Os principais meta-caracteres de expressão regular (caracteres especiais) e sequências especiais que podem ser utilizados no módulo Python 3 re são os seguintes

metacaracterconteúdo
.Qualquer caractere que não seja uma nova linha (incluindo uma nova linha com a bandeira DOTALL)
^O início da corda (também corresponde ao início de cada linha com a bandeira MULTILINE)
$O fim do fio (também corresponde ao fim de cada linha com a bandeira MULTILINE)
*Repetir o padrão anterior mais de 0 vezes
+Repetir o padrão anterior pelo menos uma vez.
?Repetir o padrão anterior 0 ou 1 vezes
{m}Repetir o padrão anterior m vezes
{m, n}O último padrão.m~nrepetir
[]Um conjunto de caracteres[]Corresponde a qualquer uma destas personagens
|OUA|BCorresponde a um padrão A ou B
sequência especialconteúdo
\dUnicode números decimais (limitados a números ASCII por bandeira ASCII)
\D\dO que significa o oposto disto.
\sCaracteres do espaço em branco Unicode (limitado aos caracteres do espaço em branco ASCII pela bandeira ASCII)
\S\sO que significa o oposto disto.
\wCaracteres unicodais das palavras e sublinhados (limitados a caracteres alfanuméricos ASCII e sublinhados por bandeira ASCII)
\W\wO que significa o oposto disto.

Nem todos eles estão listados nesta tabela. Ver a documentação oficial para uma lista completa.

Note-se também que alguns dos significados são diferentes em Python 2.

Pôr a bandeira

Como mostra a tabela acima, alguns meta-caracteres e sequências especiais mudam o seu modo dependendo da bandeira.

Apenas as bandeiras principais estão aqui cobertas. Ver a documentação oficial para o resto.

Limitado a caracteres ASCII: re.ASCII

\wIsto também corresponderá por defeito a kanji de duplo byte, caracteres alfanuméricos, etc., para as cordas Python 3. Não é equivalente ao seguinte porque não é uma expressão padrão regular.[a-zA-Z0-9_]

m = re.match(r'\w+', '漢字ABC123')
print(m)
# <re.Match object; span=(0, 11), match='漢字ABC123'>

m = re.match('[a-zA-Z0-9_]+', '漢字ABC123')
print(m)
# None

Se especificar re.ASCII para as bandeiras de argumento em cada função, ou adicionar a seguinte bandeira em linha ao início da cadeia padrão de expressão regular, apenas coincidirá com caracteres ASCII (não coincidirá com caracteres de duplo byte japoneses, alfanuméricos, etc.).
(?a)
Neste caso, os dois seguintes são equivalentes.
\w=[a-zA-Z0-9_]

m = re.match(r'\w+', '漢字ABC123', flags=re.ASCII)
print(m)
# None

m = re.match(r'(?a)\w+', '漢字ABC123')
print(m)
# None

O mesmo se aplica quando se compila com re.compile(). Utilizar as bandeiras de argumento ou bandeiras em linha.

p = re.compile(r'\w+', flags=re.ASCII)
print(p)
# re.compile('\\w+', re.ASCII)

print(p.match('漢字ABC123'))
# None

p = re.compile(r'(?a)\w+')
print(p)
# re.compile('(?a)\\w+', re.ASCII)

print(p.match('漢字ABC123'))
# None

O ASCII também está disponível como o formulário curto re. A. Pode utilizar qualquer um dos dois.

print(re.ASCII is re.A)
# True

\W, o oposto de W, é também afectado por re.ASCII e bandeiras em linha.

m = re.match(r'\W+', '漢字ABC123')
print(m)
# None

m = re.match(r'\W+', '漢字ABC123', flags=re.ASCII)
print(m)
# <re.Match object; span=(0, 11), match='漢字ABC123'>

Tal como com \w, os dois seguintes correspondem a caracteres de byte único e duplo por defeito, mas estão limitados a caracteres de byte único se forem especificadas bandeiras re.ASCII ou inline.

  • Corresponder os números\d
  • Corresponde a um espaço em branco\s
  • Corresponde a não-números\D
  • Corresponde a qualquer não espacial.\S
m = re.match(r'\d+', '123')
print(m)
# <re.Match object; span=(0, 3), match='123'>

m = re.match(r'\d+', '123')
print(m)
# <re.Match object; span=(0, 3), match='123'>

m = re.match(r'\d+', '123', flags=re.ASCII)
print(m)
# <re.Match object; span=(0, 3), match='123'>

m = re.match(r'\d+', '123', flags=re.ASCII)
print(m)
# None

m = re.match(r'\s+', ' ')  # full-width space
print(m)
# <re.Match object; span=(0, 1), match='\u3000'>

m = re.match(r'\s+', ' ', flags=re.ASCII)
print(m)
# None

Não sensível a maiúsculas e minúsculas:re.IGNORECASE

Por defeito, é sensível a maiúsculas e minúsculas. Para corresponder a ambos, é necessário incluir tanto letras maiúsculas como minúsculas no padrão.

re.IGNORECASESe isto for especificado, coincidirá de forma insensível com o caso. Equivalente à bandeira i em expressões padrão regulares.

m = re.match('[a-zA-Z]+', 'abcABC')
print(m)
# <re.Match object; span=(0, 6), match='abcABC'>

m = re.match('[a-z]+', 'abcABC', flags=re.IGNORECASE)
print(m)
# <re.Match object; span=(0, 6), match='abcABC'>

m = re.match('[A-Z]+', 'abcABC', flags=re.IGNORECASE)
print(m)
# <re.Match object; span=(0, 6), match='abcABC'>

Pode usar menos ou igual a.

  • bandeira em linha(?i)
  • abreviaturare.I

Combinar o início e o fim de cada linha:re.MULTILINE

^Os meta caracteres desta expressão regular correspondem ao início da corda.

Por defeito, apenas o início de toda a linha é correspondido, mas o que se segue corresponderá também ao início de cada linha. Equivalente à bandeira m em expressões padrão regulares.
re.MULTILINE

s = '''aaa-xxx
bbb-yyy
ccc-zzz'''

print(s)
# aaa-xxx
# bbb-yyy
# ccc-zzz

result = re.findall('[a-z]+', s)
print(result)
# ['aaa', 'xxx', 'bbb', 'yyy', 'ccc', 'zzz']

result = re.findall('^[a-z]+', s)
print(result)
# ['aaa']

result = re.findall('^[a-z]+', s, flags=re.MULTILINE)
print(result)
# ['aaa', 'bbb', 'ccc']

$Corresponde ao fim do cordel. Por defeito, apenas o final de toda a corda é correspondido.
re.MULTILINESe especificar isto, também coincidirá com o final de cada linha.

result = re.findall('[a-z]+$', s)
print(result)
# ['zzz']

result = re.findall('[a-z]+$', s, flags=re.MULTILINE)
print(result)
# ['xxx', 'yyy', 'zzz']

Pode usar menos ou igual a.

  • bandeira em linha(?m)
  • abreviaturare.M

Especificar bandeiras múltiplas

|Se quiser activar várias bandeiras ao mesmo tempo, utilize isto. No caso de bandeiras em linha, cada carácter deve ser seguido por uma letra, como se mostra abaixo.
(?am)

s = '''aaa-xxx
漢漢漢-字字字
bbb-zzz'''

print(s)
# aaa-xxx
# 漢漢漢-字字字
# bbb-zzz

result = re.findall(r'^\w+', s, flags=re.M)
print(result)
# ['aaa', '漢漢漢', 'bbb']

result = re.findall(r'^\w+', s, flags=re.M | re.A)
print(result)
# ['aaa', 'bbb']

result = re.findall(r'(?am)^\w+', s)
print(result)
# ['aaa', 'bbb']

Jogos gananciosos e não gananciosos

Este é um problema geral com expressões regulares, não apenas um problema com Python, mas vou escrever sobre ele porque tende a colocar-me em apuros.

Por defeito, o seguinte é uma partida gananciosa, que corresponde ao maior número possível de cordas.

  • *
  • +
  • ?
s = 'aaa@xxx.com, bbb@yyy.com'

m = re.match(r'.+com', s)
print(m)
# <re.Match object; span=(0, 24), match='aaa@xxx.com, bbb@yyy.com'>

print(m.group())
# aaa@xxx.com, bbb@yyy.com

O ? depois dele resultará numa combinação não mesquinha e mínima, correspondendo à corda mais curta possível.

  • *?
  • +?
  • ??
m = re.match(r'.+?com', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

print(m.group())
# aaa@xxx.com

Note-se que o jogo ganancioso por defeito pode corresponder a cordas inesperadas.

Copied title and URL