Documente Academic
Documente Profesional
Documente Cultură
Comentário do autor
Antes de começar a chatear a cabeça às pessoas, é melhor eu dizer umas coisinhas sobre Regex (também conhecidas por Regular
Expressions).
Regexs não é complicado de escrever, pode ser complicado é de ler as regexs feitas pelos outros (existe uma maneira de
atenuar/evitar essa situação que eu vou explicar mais para a frente, mas se são impacientes, procurem por re.VERBOSE aqui
no guia, que não falham).
Regexs não é a cura para todos os males. O que quero dizer é que nem sempre regexs são a melhor maneira de atacar um
problema. Existe um ditado (o livro onde isso está escrito está na casa-de-banho e não me apetece ir lá ) que é algo assim
“When confronted with a problem, people often think 'I know, I'll use Regular Expressions'. Now they have two problems.”
Da mesma forma, usar regex não vos torna l33t, nem faz com que as raparigas se apaixonem por vocês (no entanto, se
arranjarem alguma dessas, dêem-me o email dela )
>>> import re
E está feito.
Se o método re.search encontrar a pattern na string a comparar, faz return de um match object que tem alguns métodos que
vou explicar mais à frente (mas só vou explicar alguns ).
É claro que isto é tudo muito bonito e tal mas não seria mais simples fazer:
Por acaso era mais simples E mais eficiente. Este é um daqueles casos em que não é necessário usar regex.
Caracteres especiais
Como regex é uma espécie de linguagem própria, existem caracteres que têm algum significado especial quando usados na
pattern.
Eles são:
( )
[ ]
^ $
.
* + ? { }
| \
Tudo o que escreverem dentro dos ( ) é guardado quando fizerem re.search() numa variável para poderem aceder mais tarde
usando re.search().groups().
Por exemplo:
…portugal-a-programar.org/python:re… 1/6
27/02/2011 Expressões Regulares em Python [Wiki …
>>> pattern = re.compile("(lol)")
>>> re.search(pattern, string_a_comparar).groups()
('lol',)
Isto pode parecer estúpido inicialmente, pois se estamos a verificar que o “lol” existe na string a comparar, é claro que ele vai lá
estar no groups(). Mas isto vai servir para muita coisa, já daqui a um bocado.
NEXT!
EXEMPLO TIME!
OPS! O re.search apenas fez return do primeiro “d” (que é a primeira letra da string_a_comparar que existe na regex ”[abcdef]”)
Então o que fazer? Bem, há duas coisas a fazer. Primeiro, pode-se modificar a regex para incorporar repetição (que vou explicar
mais à frente), ou pode-se usar outro método para além do re.search.
Por agora vamos utilizar outro método, o re.findall() (só quero explicar como fazer repetições mais para a frente :D).
No entanto, existe também outro carácter que podem usar dentro dos [ ] que também tem um significado especial, o ^ no início
do [ ].
O ^ faz com que a regex procure aquilo que não esteja dentro dos [ ].
Por exemplo, [^012345] ( ou então [^0-5]) só ia procurar por 6, 7, 8 e 9 e os restantes caracteres (“a”, “b”, “c”, ”.”, etc.).
No entanto o ^ também tem um significado especial se tiver fora dos [ ] que vou dizer de seguida.
Por exemplo:
>>> re.search(pattern, "1234lolasdfasdf") # Isto nao vai funcionar porque o "lol" nao se encontra no inicio da string
>>> re.search(pattern, "asdfasdlolf") # Isto nao vai dar funcionar porque o "lol" nao se encontra no fim da string
Um . é o mesmo que ter [a-zA-Z0-9 ] (o espaço no final é propositado, serve para fazer o regex apanhar também os espaços em
branco) mais uns caracteres especiais para coisas como tabs, etc., ou melhor ainda [^\n].
…portugal-a-programar.org/python:re… 2/6
27/02/2011 Expressões Regulares em Python [Wiki …
>>> pattern = re.compile(".")
>>> re.findall(pattern, "sl234 kgj")
['s', 'l', '2', '3', '4', ' ', 'k', 'g', 'j']
Por exemplo:
O ”+” é parecido com o “*”, excepto que significa “procurar por 1 ou mais vezes”.
O ”?” é também parecido com o “*” e o ”+”, excepto que significa “procurar por 0 ou 1 vezes”.
>>> re.search(pattern, "lool") # Nao resulta em nada porque o "o" existe mais do que uma vez
A SÉRIO! É IMPORTANTE!
(estejam atento pelo menos a esta parte).
Aliás, isto é tão importante que o melhor que têm a fazer é imprimir esta página e recortar esta parte e colar à beira do monitor,
do espelho da casa-de-banho, debaixo da almofada e no frigorífico (podem arranjar ímanes num disco rígido velho se for preciso).
Imaginemos que queremos recolher o conteúdo das tags de uma página de HTML (vamos simular uma página de HTML com a
string ”<p> <img href='lol' /> df </p>”).
A primeira ideia provavelmente seria usar uma regex do género ”<(.*)>”, ou seja, procurar por todos os caracteres que apareçam
0 ou mais vezes (é para isso que o ”.*” serve), guardar os valores para usar mais tarde ( é para isso que os () servem), e que
estejam dentro de < > (estes caracteres não têm nenhum significado especial para a regex), e provavelmente usar o re.findall(),
senão só ia reagir ao primeiro <p>.
Ok… Não era bem esta a ideia que queríamos/queria (se não percebam o que tinha dito antes, a ideia seria obter algo do género
[“p”, “img href='lol' /”, ”/p”]).
O problema é que o “*” e o ”+” fazem aquilo que se chama “greddy match”. Isso significa que o regex vai tentar apanhar o
máximo da string possível, ou neste caso, do primeiro ”<” ao último ”>” existente na string (que se encontra em no ”</p>”).
Como a inveja é um pecado mortal (pelo menos na religião cristã), e não queremos que nenhuma regex vá para o /dev/null, temos
que usar o que se chama de “non-greddy match”.
…portugal-a-programar.org/python:re… 3/6
27/02/2011 Expressões Regulares em Python [Wiki …
E como é que se faz isso? Simples, adiciona-se um ? depois do ”.*”. Ou seja:
Agora porque razão é que disse para prestarem muita atenção a isto? Porque o ”?” pode também significar, tal como já tinha dito,
“procurar o carácter 0 ou 1 vezes”, e também porque é muito importante saber o que é uma “greddy match” e uma “non-greddy
match” (nem vos passa as dores de cabeça que passei antes de descobrir isto :P).
Ou seja, se o ”?” estiver depois de um “*” ou um ”+”, significa “non-greddy match”, senão significa “procurar o carácter 0 ou 1
vezes”.
Os { } levam dois valores lá dentro, por exemplo {2,5}, (não pode ser {2, 5}, tem que ser tudo junto) que significa “apanhar o
carácter se ele estiver repetido 2, 3, 4 ou 5 vezes”.
Vamos lá ver:
Se não escrevem um valor, o python usa o valor mais lógico para preencher essa falha. Por exemplo, {,5} transforma-se em
{0,5} e {5,} transforma-se em {5,+infinito} (ok, nada na informática é infinito em termos de armazenamento, mas é utilizado o
maior valor possível (alguns biliões), que, acho eu, corresponde ao valor máximo do int em C, mas se arranjarem uma string com
biliões de caracteres então o vosso problema não está na regex :P).
Como eu sei que são todos uns tipos/as muito inteligentes, estou certo que já reparam que “*” é o mesmo que {0,} ou {,} , ”+”
é o mesmo que {1,} e ”?” (inserir aviso sobre evitar a confusão com o símbolo de “non-greddy match” aqui) é o mesmo que
{0,1}.
Porém é melhor usarem os símbolos “*”, ”+”, ”?”, para facilitar a leitura das regex (acreditem que ajuda a ler E ainda poupam as
teclas do teclado).
O carácter especial |
O | apenas significa OU. Por exemplo, usar “lol|lulz” significa procurar por “lol” ou “lulz”.
>>> re.search(pattern, "SPARTAAAAAAAA") # Nao activa porque nao esta no conjunto ("lol", "lulz")
O carácter especial \
Tudo o que ele faz é transformar um carácter especial num carácter normal. Por exemplo, se quiserem procurar por um ”[” ou por
um ”]”, não podem simplesmente colocar um ”[” ou ”]” na regex, por esses são dois caracteres que tem um significado muito
específico na regex. Como tal têm que dizer ao módulo re para ignorar esses caracteres, ou colocar um \ antes deles. Ou seja,
em vez de ”[” ”]” passamos a usar “\[” e “\]”.
No entanto existe um problema com a forma com o Python trata o carácter \ . É que também ele significa para o Python ignorar o
carácter seguinte. Teriam então que usar “\\[” ou “\\]”, OU (a maneira mais indicada neste caso) escrever a string da regex no
seguinte formato:
…portugal-a-programar.org/python:re… 4/6
27/02/2011 Expressões Regulares em Python [Wiki …
>>> pattern = re.compile(r"\[ \]")
>>> re.search(pattern, "12[ ]21")
<_sre.SRE_Match object at 0x8614758>
Reparem no “r” que está no pattern. Para quem não sabe, colocar um “r” antes de uma string (qualquer que seja), indica ao
Python para ignorar todos os caracteres considerados pelo Python (não pelo módulo re). O “r” vem de “raw”. Por exemplo:
teste
>>> print r"\nteste"
\nteste
Por isso já sabem, se quiserem usar o \ numa regex, não se esquecem de transformar essa string numa string “raw”. Senão
podem acabar com algo assim: “\\\\”, ou seja, dizer ao python para ignorar dois \, que por sua vez diz ao módulo re para ignorar
um \ :P
E são estes os caracteres especiais todos de uma regex em Python. (Hum… Acho que me alonguei um bocado, o Vim indica quase
313 linhas escritas… Bem lá tem que ser).
Teoricamente, podem escrever qualquer regex usando o que está escrito até agora, mas existem uns atalhos jeitosos para
algumas das combinações mais usadas.
\s (Procurar por qualquer espaço em branco, ou seja [ \t\n\r\f\v] (whitespace, tabs, newlines, return carriages, etc.))
\S (Procurar por qualquer carácter que não seja um espaço em branco, ou seja, [^ \t\n\r\f\v])
Por exemplo, podem usar [\d|\s] para procurar por números e espaços em branco.
Lembram-se de eu ter falado sobre os modos do re.compile, à cerca de 300 linhas atrás? Pois bem, chegou a hora de falar neles.
:P
re.DOTALL
Este modo apenas faz com o carácter especial ”.” apanhe também o “\n” (normalmente pára quando encontra esse carácter).
Isto é bom por exemplo se tivermos uma string com várias linhas.
E POR FIM…
re.VERBOSE
Este é o modo que mais contribui para se poder escrever regex que sejam legíveis. Basicamente, neste modo, o módulo re ignora
todo o espaço em branco que não esteja dentro de [ ], e permite também escrever comentários dentro da regex.
Vamos lá ver:
>>> pattern = re.compile(""" # Nao se esquecam de usar 3 ' para indicar uma string que dura varias linhas
# Ah, qualquer coisa escrita apos um # e considerado um comantario
# Tal como no Python normal :P
…portugal-a-programar.org/python:re… 5/6
27/02/2011 Expressões Regulares em Python [Wiki …
>>> re.search(pattern, "lldldldldldl ").groups()
(' ',)
python/regex.txt · E s ta página foi modific ada pela última vez em: 2 0 1 0 /0 8 /0 2 2 1 :2 7 por anols i
…portugal-a-programar.org/python:re… 6/6