Expressões Regulares
Abstrato::
expressões regulares que são usadas para contexto avançado em procuras sensíveis e modificações de texto. Eles podem ser achados em muitos editores avançados, e em programas de editoração eletronica e em idiomas.
Introdução
As Expressões Regulares podem ser encontradas em muitos editores como vi, emacs, e em programas como grep, egrep e em linguagens de programação como awk, perl e sed.
As Expressões Regulares são usadas para buscas avançadas dependendo do contexto. Por isso podemos dizer que as Expressões Regulares não são apenas um localizador de cadeias de texto,
sim que são a descrição formal de um protetor do texto.
Quando ví pela primeira vez como poderíamos editar textos com a ajuda das Expressões Regulares, fiquei fascinado. Modificações em um texto, para os que os tivesse utilizado durante horas, ficavam prontas em poucos segundos. O que com certeza se veria no monitor, parecia um conjunto de pontos, hífens e outros símbolos. Com certeza alguma coisa estava claro: Queria aprender a linguagem das Expressões Regulares e o que me deixou impressionado, era a facilidade para entender. Segue abaixo, algumas regras de sintaxe muito simples.
Apesar de que as Expressões Regulares estejem muito extendidas no mundo Unix, não existe uma linguagem standard de Expressões Regulares. Mas se bem que poderemos falar de diferentes dialetos. Existem por exemplo dois representantes do conhecido programa grep, egrep e grep. Ambos usam as Expressões Regulares com capacidades ligeiramente diferentes. Perl pode ser qualificada como a linguagem com a sintaxe de Expressões Regulares mais desenvolvida. Com sorte todos estes dialetos seguem os mesmos princípios e no momento em que os entendemos, o resto será fácil.
Neste artigo me dedicarei exclusivamente aos príncipios básicos, os detalhes que poderemos consultar nas páginas dos manuais (man-pages).
Um pequeno exemplo
Suponhamos que tenhamos a seguinte lista de telefones de uma empresa:
Fone Nome ID
...
...
3412 Bob 123
3834 Jonny 333
1248 Kate 634
1423 Tony 567
2567 Peter 435
3567 Alice 535
1548 Kerry 534
...
Estamos tratando com uma empresa com 500 pessoas e os dados estão armazenados em um arquivo ASCII normal. Os registros de pessoas cujo telefone comece com 1, trabalham no edifício 1. Quem trabalha no Edifício 1?
Uma Expressão Regular poderá responder a esta questão:
grep '^1' phonelist.txt
ou
egrep '^1' phonelist.txt
ou
perl -ne 'print if (/^1/)' phonelist.txt
Em palavras normais isto significa: Procura todas as linhas que comecem com um 1. O símbolo "^" é o encarregado de indicar que sómente encontrem os números 1 que se encontrem no príncipio da linha.
Regras de sintaxe
Padrão só com um símbolo
O elemento básico de uma expressão regular é o padrão de só um símbolo. Este padrão
sómente é efetivado quando este símbolo puder ser encontrado exatamente como o texto.
Um exemplo do que podemos encontrar com o número 1 do exemplo acima.
Outro exemplo para o padrão de só um símbolo
é:
egrep 'Kerry' phonelist.txt
Este padrão se compõe de padrões de só um símbolo (a letra K, e, etc.)
Vários signos podem ser agrupados em um conjunto. Um conjunto é representado com um par de colchetes (o de abrir e o de fechar) e uma lista de caracteres entre eles. Um conjunto também
é considerado como um padrão de só um símbolo. A busca deste conjunto se efetivará quando encontramos um e só um dos signos do conjunto do texto. Um exemplo:
[abc] Um padrão de um só símbolo com o
qual poderemos encontrar o símbolo a, b ou c.
[ab0-9] Um padrão de só um símbolo no qual
se procura um a ou um b ou um número
que se encontre entre o 0 e o 9 no código ASCII.
[a-zA-Z0-9\-] Este procura uma letra maiúscula ou minúscula
ou um número ou o signo -.
Numa lista de telefone:
egrep '^1[348]' phonelist.txt
Esta expressão procura linhas que comecem com 13, 14 ou 18.
A maioria dos símbolos ASCII nos leva a uma busca hesitante quando se procura no texto, mas também encontramos símbolos em uma expressão regular que tem um significado especial. Os colchetes até a direita indicam o começo da definição de um conjunto. O símbolo "-" em um conjunto é um símbolo especial e representa uma categoria especial no sistema de símbolos
ASCII. Para indicar que nos referimos ao significado normal do símbolo, se coloca uma barra invertida antes "\". Por exemplo, na expressão [a-zA-Z0-9\-]. Em alguns dialetos encontramos que a barra invertida junto a outro símbolo tem um significado especial. Neste caso se obtem o significado normal retirando a barra invertida.
O ponto também é um símbolo importante em uma expressão regular. A busca será efetiva
quando o símbolo comparado seja qualquer símbolo menos o símbolo de nova linha do código
ASCII.
Exemplo:
grep '^.2' phonelist.txt
Esta expressão procura linhas que contenham o número 2 na segunda posição e qualquer outro símbolo antes.
Os pontos podem ser invertidos mediante a colocação de "[^" en lugar de "[" na expressão. Neste caso o símbolo "^" não representa o começo da linha, sim que "[" e "^" juntos representam o inverso do conjunto.
[0-9] Um padrão de só um símbolo, a procura
será efetivada se o símbolo no texto é um número.
[^0-9] Tudo o que seja um número.
[^abc] Tudo o que seja um a, b ou c.
. Tudo menos o símbolo de linha nova. É identico a
[^\n]. \n é o símbolo para uma nova linha.
Para procurar todas as línhas que NÃO comecem com um 1, escreveríamos:
egrep '^[^1]' phonelist.txt
Âncoras (anchors)
Antes vimos que "^" representava o início de uma linha. As âncoras são símbolos especiais
nas expressões regulares que não demonstram um símbolo e sim uma posição.el inicio de una
^ Inicio de uma linha
$ Final de uma linha
Para encontrar pessoas em nossa lista com um indicativo company-ID) de 567, utilizaremos a expressão:
egrep '567$' phonelist.txt
Significa: Procure linhas que finalizem com 567.
Multiplicadores
Os multiplicadores nos indicam, quantas vezes tem de aparecer um padrão de só
um símbolo no texto:
Descrição | grep | egrep | perl | vi | vim | vile
| elvis | emacs |
zero ou mais vezes | * | * | * | * | * | * | * | * |
uma ou mais vez | \{1,\} | + | + | | \+ | \+ | \+ | + |
zero o uma vez | \? | ? | ? | | \= | \? | \= | ? |
de n até m vezes | \{n,m\} | | {n,m} | | | | \{n,m\} | \{n,m\} |
Nota: Para os distintos VI teria que utilizar a opção magic.
Um exemplo da lista de telefones:
....
1248 Kate 634
....
1548 Kerry 534
....
Para encontrar uma página que se componha de um 1, vários números, vários espaços e a letra K, escreveríamos:
grep '^1[0-9]\{1,\} \{1,\}K' phonelist.txt
ou utilizaríamos * e repetimos [0-9] e o espaço:
grep '^1[0-9][0-9]* *K' phonelist.txt
ou
egrep '^1[0-9]+ +K' phonelist.txt
ou
perl -ne 'print if (/^1[0-9]+ +K/)' phonelist.txt
Os multiplicadores nos indicam, quantas vezes tem que aparecer o padrão de só um
símbolo que os precede. "23*4" NÃO significa "2, 3, talvéz alguma coisa e depois
um 4" (isto seria "23.*4"), senão que significa, que se está buscando "un 2, talvéz
alguns 3 e um 4".
É importante saber que um multiplicador é ávido. Isto significa que o primeiro multiplicador se extenderá ao máximo que possa até a direita.
Isto não é muito importante no grep, mas, é importante no momento de editar textos.
A expressão ^1.*4
se extenderia por toda linha
1548 Kerry 534
do início até o fim.
A expressão não se extende sómente até a zona curta, o seja, 154, senão até o máximo
que possa.
Parenteses como memoria
Os parentesis como memória não influem no tipo ou símbolos que se busca. Servem para que
os fragmentos do texto se armazenem e possamos encontrá-los através de variáveis.
O primeiro parentese será referenciado como variável 1, o segundo como variável 2, etc.
Nome do programa | Sintaxe do parentese | Sintaxe das variáveis |
grep | \(\) | \1 |
egrep | () | \1 |
perl | () | \1 or ${1} |
vi,vim,vile,elvis | \(\) | \1 |
emacs | \(\) | \1 |
Um exemplo:
A expressão [a-z] [a-z]
procura duas letras minúsculas.
Agora podemos utilizar estas variáveis, para procurar padrões de texto como ?otto?:
egrep '([a-z])([a-z])\2\1'
A variável \1 comtém a letra o
e \2 a letra t.
A expressão serviria também para anna, mas não para yxyx.
Os parenteses não são utilizados normalmente para procura de nomes como otto e anna,
senão para editar ou para procurar e substituir.
Uso das Expressões Regulares para o tratamento de Textos
Para editar textos é necessário um editor de textos como vi ou emacs ou perl.
Todos estes programas suportam expressões regulares.
No emacs utilizamos M-x query-replace-regexp ou replace-regexp. M-x query-replace-regexp
pede confirmação em cada procura e substituição. O mais recomendável é atribuir uma tecla de função ao query-replace ou replace-regexp.
No vi utilizamos :%s/ / /gc. O símbolo % representa a Ex-região ?todo o arquivo? no que podemos recomeçar por qualquer outra Ex-region. No editor vim, por exemplo, podemos marcar uma região com maiúscula-v e o cursor acima/abaixo. Desgraçadamente o artigo sairia de seus
propósitos sem que não déssemos uma pequena introdução sobre vim. ///gc é interativo e
pede por uma confirmação. s///g não é interativo. No perl utilizamos:
perl -pe 's/ / /g'
Agora alguns exemplos. Na empresa temos que modificar alguns telefones. Todos os telefones
que começam com um 1, tem que ter um 2 depois do segundo número. De 1423 passaremos para
14223.
Fone Nome ID
...
3412 Bob 123
3834 Jonny 333
1248 Kate 634
1423 Tony 567
2567 Peter 435
3567 Alice 535
1548 Kerry 534
...
e isto é assim de fácil:
vi: s/^\(1.\)/\12/g
emacs: ^\(1.\) sustituir por \12
perl: perl -pe 's/^(1.)/${1}2/g' phonelist.txt
A lista de telefones aparecerá assim:
Fone Nome ID
...
3412 Bob 123
3834 Jonny 333
12248 Kate 634
14223 Tony 567
2567 Peter 435
3567 Alice 535
15248 Kerry 534
...
Perl não sómente conhece as variáveis \1 \9. \12 apontaria para a
variável 12. Para solucionar o problema utilizamos simplesmente ${1}.
Mas agora não encontramos as colunas bem alinhadas.
Como poderíamos solucionar
isto? Poderíamos comprovar se há um espaço na quinta
posição e inserir outro.
vi: s/^\(....\) /\1 /g
emacs: '^\(....\) ' sustituir por '\1 '
perl: perl -pe 's/^(....) /${1} /g' phonelist.txt
Agora temos:
Fone Nome ID
...
3412 Bob 123
3834 Jonny 333
12248 Kate 634
14223 Tony 567
2567 Peter 435
3567 Alice 535
15248 Karry 534
...
Um colega editou a phonelist.txt e não teve o devido cuidado.
No princípio de alguma linha encontramos espaços. Como poderemos solucionar?
Fone Nome ID
...
3412 Bob 123
3834 Jonny 333
12248 Kate 634
14223 Tony 567
2567 Peter 435
3567 Alice 535
15248 Kerry 534
...
Isto terá que solucionar o problema:
vi: s/^ *// (existem dois espaços, já que não temos o +)
emacs: '^ +' substituir pela cadeia vazia
perl: perl -pe 's/^ +//' phonelist.txt
Estás escrevendo um programa e utiliza as variáveis
temp y temporary. Agora queres substituir a variavel temp pela variável
counter. Se utilizasse a opção de procurar e substituir,verias
que a variável temporary seria substituida por counterorary. Isto
queres evitar.
Com as expressões regularesfaremos bem fácil. Se
substituirmos temp([^o]) com counter\1. Com isto, substituiremos temp e não "o".
(Outra alternativa seriam as Boundaries, que não foi comentada aqui.)
Espero que este artigo tenha despertado sua curiosidade. Se desejas continuar, sugiro consultar as man-pages de teu editor preferido.
Existem mais símbolos especiais nas expressões regulares, como por exemplo,
Alterations, Art Order, e naturalmente as Boundaries.
Que disfrutes então
|