Lecture at III meeting of Python Users Group of Pernambuco at 17/02/2010.
Title: Regular Expressions and Python.
Portuguese lecture.
Título: Python e Expressões regulares. Palestra ministrada no III PUG-PE.
2. O que são Expressões
Regulares ?
Também chamado de regex ou regexp
Ferramenta eficiente para processamento de
palavras em texto por meio de casamento
padrões.
Linguagem formal que pode ser interpretada
por um processador de expressões regulares
ou por um programa que identifica partes do
texto que “casam”com uma especificação
provida. - Wikipedia
III Encontro do PUG-PE
3. O que são Expressões
Regulares ? (Exemplos)
Sequência de caracteres ‘car’ em qualquer
conteto, como em “car”, “cartoon”, “bicarbonate”
A palavra “car” quando aparece isoladamente
A palavra “car” quando precedida de “blue” or
“red”
Símbolo $ seguido por 1 ou mais dígitos, e após,
opcionalmente, um . seguido por mais 2 dígitos.
III Encontro do PUG-PE
4. Mas antes um pouco de
História...
Estão na teoria dos automâtos e linguagens
formais
Descrição e classificação de linguagens formais
Na década de 50, Stephen Kleene criou sua
notação (conjuntos regulares) formando a
algébra de Kleene
Realmente usáveis a partir da biblioteca escrita
para tcl e Perl, definindo a PCRE.
III Encontro do PUG-PE
5. Python e Expressões Regulares
O módulo re é o responsável!
Mas por onde começamos ?!
III Encontro do PUG-PE
6. re - Elementos básicos
a,X, 9 caracteres normais, casam com eles mesmos exatamente
. casam com qualquer caractere exceto n
w casam com qualquer letra ou dígito ou _ [a-zA-Z0-9_]. Apenas 1 caractere!!!
W casam com qualquer não caractere (o complemento de w)
b casa a separação de palavras.
s casa com o caractere espaço em branco, quebra de linha, tab, form [ nrtf].
S casa com qualquer não caractere acima [ complemento de s]
t n r - tab newline e return
d digitos [0-9]
^ início ou $ fim - casam com o início ou fim da string
Inibe os caracteres especiais acima.
Ex: . (casa com um ponto) , (casa com uma ).
III Encontro do PUG-PE
7. re - Alguns comandos básicos
match = re.search(pat, str)
re.search() - Recebe uma expressão regular e uma
string. Procura por padrões que satisfazem a
especificação dada.
III Encontro do PUG-PE
8. re - Alguns comandos básicos
str = 'an example word:cat!!'
match = re.search(r'word:www', str)
# O if testa se o search obteve sucesso.
if match:
print 'found', match.group() ## 'achou word:cat'
else:
print 'did not find'
Retorna None se a busca foi falha. Senão retorna
um objeto match
III Encontro do PUG-PE
9. search - Algumas regras básicas
A busca varre sobre a string do ínicio ao fim,
interrompendo no primeiro match encontrado.
Todo o padrão tem que ser satisfeito e não toda
string.
match.group() retorna o texto identificado.
III Encontro do PUG-PE
10. re - Alguns comandos básicos
## Search for pattern 'iii' in string 'piiig'.
## All of the pattern must match, but it may appear anywhere.
## On success, match.group() is matched text.
match = re.search(r'iii', 'piiig') => found, match.group() == "iii"
match = re.search(r'igs', 'piiig') => not found, match == None
## . = any char but n
match = re.search(r'..g', 'piiig') => found, match.group() == "iig"
## d = digit char, w = word char
match = re.search(r'ddd', 'p123g') => found, match.group() == "123"
match = re.search(r'www', '@@abcd!!') => found, match.group() == "abc"
Retorna None se a busca foi falha. Senão retorna
um objeto match
III Encontro do PUG-PE
11. re - Repetição
+ Uma ou mais ocorrências do elemento precedente ex: i+ (1 ou mais ‘i’s)
* 0 ou mais ocorrências do elemento precedente
? Casa 0 ou 1 ocorência do elemento precedente
III Encontro do PUG-PE
12. re - Repetição
São operadores Greedy e LeftMost
Tentam achar o padrão mais à esquerda e tentam
consumir a string o máximo possível.
III Encontro do PUG-PE
13. re - Repetição
## i+ = one or more i's, as many as possible.
match = re.search(r'pi+', 'piiig') => found, match.group() == "piii"
## Finds the first/leftmost solution, and within it drives the +
## as far as possible (aka 'leftmost and largest').
## In this example, note that it does not get to the second set of i's.
match = re.search(r'i+', 'piigiiii') => found, match.group() == "ii"
## s* = zero or more whitespace chars
## Here look for 3 digits, possibly separated by whitespace.
match = re.search(r'ds*ds*d', 'xx1 2 3xx') => found, match.group() == "1 2 3"
match = re.search(r'ds*ds*d', 'xx12 3xx') => found, match.group() == "12 3"
match = re.search(r'ds*ds*d', 'xx123xx') => found, match.group() == "123"
## ^ = matches the start of string, so this fails:
match = re.search(r'^bw+', 'foobar') => not found, match == None
## but without the ^ it succeeds:
match = re.search(r'bw+', 'foobar') => found, match.group() == "bar"
III Encontro do PUG-PE
14. re - Alguns comandos básicos
pattern = re.compile(pat)
pattern.match(str)
re.compile() - Permite compilar a expressão regular e
retorna um objeto SRE_Pattern
re.match() - retorna None se a string não atender as
especificações e ao contrário um objeto Match.
III Encontro do PUG-PE
15. Exemplos práticos
Temos o texto a seguir:
'xyz alice-b@google.com purple monkey'
Como extrairmos o e-mail deste e-mail ?!
III Encontro do PUG-PE
16. Exemplos práticos
Tentativa 01
r'w+@w+':
Entrada: 'xyz alice-b@google.com purple monkey'
Saída: b@google
III Encontro do PUG-PE
17. Exemplos práticos
str = 'purple alice-b@google.com purple monkey'
match = re.search(r'w+@w+', str)
if match:
print match.group() ## 'b@google'
Problema! w não captura . ou -
III Encontro do PUG-PE
18. Antes..
[ ] - Lista de caracteres. Casa uma ocorrência de
qualquer caractere na lista. [abc] casa ‘a’, ‘b’ou ‘c’.
Define Intervalos de caracteres ex: [a-z] ou [0-9]
Caracteres
Caracteres especiais como - ou .
são considerados literais dentro
da lista.
III Encontro do PUG-PE
19. Exemplos práticos
Tentativa 02
r'[w.-]+@[w.-]+'
Entrada: 'xyz alice-b@google.com purple monkey'
Saída: alice-b@google.com
III Encontro do PUG-PE
20. Exemplos práticos
match = re.search(r'[w.-]+@[w.-]+', str)
if match:
print match.group() ## 'alice-b@google.com'
PS: [ˆ ] Lista negada de caracteres. Casa uma
ocorrência de qualquer caractere nõ contido na lista.
[^abc] - qualquer caractere exceto ‘a’ou ‘b’ ou ‘c
III Encontro do PUG-PE
21. Exemplos práticos
Show! Mas agora eu quero pegar partes específicas
do e-mail, e agora?!
'xyz alice-b@google.com purple monkey'
login e domínio
III Encontro do PUG-PE
22. O group() irá nos ajudar!
match.group(int) - Permite capturar partes
específicas do texto (subexpressões).
( ) - Delimita grupos de captura
dentro do padrão a ser extraído.
III Encontro do PUG-PE
23. Exemplos práticos
r'([w.-]+)@([w.-]+)'
Entrada: 'xyz alice-b@google.com purple monkey'
alice-b@google.com #match.group()
Saída: alice-b #match.group(1)
google.com #match.group(2)
III Encontro do PUG-PE
24. Exemplos práticos
str = 'purple alice-b@google.com monkey dishwasher'
match = re.search('([w.-]+)@([w.-]+)', str)
if match:
print match.group() ## 'alice-b@google.com' (the whole match)
print match.group(1) ## 'alice-b' (the username, group 1)
print match.group(2) ## 'google.com' (the host, group 2)
Ferramenta útil para extração de cadeias de
caracteres específicas do padrão.
III Encontro do PUG-PE
25. re - Comandos básicos
re.findall(patt,str)
re.findall() - Retorna todas as strings que casam
com a especificação desejada.
Retorna uma lista de strings, onde cada string
representa um padrão encontrado.
III Encontro do PUG-PE
26. Exemplos práticos
## Suppose we have a text with many email addresses
str = 'purple alice@google.com, blah monkey bob@abc.com blah dishwasher'
## Here re.findall() returns a list of all the found email strings
emails = re.findall(r'[w.-]+@[w.-]+', str)
## ['alice@google.com', 'bob@abc.com']
for email in emails:
# do something with each found email string
print email
III Encontro do PUG-PE
27. Exemplos práticos
E se minha string fosse um arquivo-texto?!
re.findall() continua sendo uma ótima solução!
# Open file
f = open('test.txt', 'r')
# Feed the file text into findall();
#it returns a list of all the found strings
strings = re.findall(r'some pattern', f.read())
III Encontro do PUG-PE
28. findall() e group() juntos!
Grupos de Captura ( ) combinado findall()
Retorna uma lista de tuplas. Cada tupla
representando um padrão encontrado, onde cada
elemento representa group(1), group(2), ...
III Encontro do PUG-PE
29. Exemplos práticos
Voltando para o nosso exemplo do e-mail
'purple alice@google.com, blah monkey bob@abc.com blah dishwasher'
Se quisermos partes específicas dos padrões?!
Vamos montar nossa expressão regular!
III Encontro do PUG-PE
31. Exemplos práticos
str = 'purple alice@google.com, blah monkey bob@abc.com blah dishwasher'
tuples = re.findall(r'([w.-]+)@([w.-]+)', str)
print tuples ## [('alice', 'google.com'), ('bob', 'abc.com')]
for tuple in tuples:
print tuple[0] ## username
print tuple[1] ## host
(?: ) Grupo de captura o qual não quer que entre nos
resultados.
III Encontro do PUG-PE
32. Dicas para criação de ER
Tente criar expressões regulares simples que tragam
mais resultados.
A idéia é ir aos poucos refinando até chegar onde
você quer.
Enfraquecido no início, forte no fim.
III Encontro do PUG-PE
33. Parâmetros opcinais para RE
Flags opcionais para funções como re.search, findall(), etc.
ex: re.search(patt, str, re.IGNORECASE)
IGNORECASE Ignore o case sensitive. Identifica ambos ‘a’ e ‘A’
DOTALL Permite (.) para casa quebra de linhas. Por padrão .* só casa
encontrar uma quebra de linha (n).
MULTILINE Permite strings de múltiplas linhas. Permite ^e $ para casar o
ínicio ou fim de cada linha.
III Encontro do PUG-PE
34. re -Substituição
re.sub(pat,replacement,str)
re.sub() - Busca por todas as instâncias do padrão
em um texto e os substitui por outro padrão.
III Encontro do PUG-PE
35. Exemplos práticos
Não entendeu?! Vamos a um exemplo!
'purple alice@google.com, blah monkey bob@abc.com blah dishwasher'
Vamos trocar todos os domínios do e-mail por
yo-yo-dyne.com
III Encontro do PUG-PE
37. Exemplos práticos
str = 'purple alice@google.com, blah monkey bob@abc.com blah dishwasher'
## re.sub(pat, replacement, str) -- returns new string with all replacements,
## 1 is group(1), 2 group(2) in the replacement
print re.sub(r'([w.-]+)@([w.-]+)', r'1@yo-yo-dyne.com', str)
## purple alice@yo-yo-dyne.com, blah monkey bob@yo-yo-dyne.com blah dishwasher
O padrão a substuir pode incluir 1 2 que se refere
no texto ao group(1), group(2), etc.. do texto original.
III Encontro do PUG-PE
38. Greedy x Non-Greedy
Vamos considerar o seguinte texto:
‘<b>foo</b> and <i>so on </i>’
E queremos pegar apenas os padrões que atendem
‘(<.*>)’ , qual é o resultado esperado ?
III Encontro do PUG-PE
39. Greedy x Non-Greedy
Retorna:
‘<b>foo</b> and <i>so on </i>’
Como assim ?!
III Encontro do PUG-PE
40. Greedy x Non-Greedy
*. é um operador guloso (‘greedy’), vai o máximo que
pode!
Soluções: .*? ou .+?
III Encontro do PUG-PE
41. Greedy x Non-Greedy
‘(<.*?>)’ irá só pegar ‘<b>’ como primeiro grupo e
<‘/b> como segundo grupo, e assim sucessivamente.
.*? Irá consumir até encontrar um marcador
procedente de ? (> neste caso) que força a parada
de .*?
III Encontro do PUG-PE
42. Ferramenta para testes de RE
Python Regex
http://www.pythonregex.com/
III Encontro do PUG-PE
44. Referências
http://pt.wikipedia.org/wiki/Express%C3%A3o_regular
http://code.google.com/edu/languages/google-python-class/regular-expressions.html
http://docs.python.org/library/re.html
III Encontro do PUG-PE