Ir para o conteúdo
ou

Software livre Brasil

 Voltar a Gustavo Dutr...
Tela cheia

Lookahead, Lookbehind e Condicionais em Expressões Regulares

30 de Dezembro de 2009, 0:00 , por Software Livre Brasil - 0sem comentários ainda | Ninguém está seguindo este artigo ainda.
Visualizado 1355 vezes

Depois de muito tempo sem postar, me lembrei de algo bem interessante! Vocês podem mandar mensagens na página de contato dando sugestões de temas sobre Vim, Expressões regulares ou outra coisa que vocês gostariam de ver no blog ;p.

Expressões Regulares

Expressão regular é uma ferramenta muito forte para o tratamento de texto. É muito utilizado para substituições ou para verificar integridade dos dados, pois, através da expressão regular, vulga regex ou re, pode-se casar padrões de texto. Por exemplo:

/^[a-zA-Z0-9]+$/
Para somente caracteres alfanuméricos.
 
/^(\d{3}\.){2}\d{3}-\d{2}$/
Validando formato de CPF.

Esse tipo de regex é simples, valida praticamente só os caracteres que compõe uma dada string. Porém, as Perl Compatible Regular Expressions (Expressões Regulares Compatíveis com Perl), também conhecidas como pcre, permitem muito mais, inclusive utilizar condicionados (if’s), porém isso é para outro post! O que vamos falar agora é de Lookahead e Lookbehind.

Lookahead

Lookahead é uma forma de casar strings que tenham ou não um determinado final. É utilizado (?⁼…) para o positivo, ou seja, que terminem com; e (?!…) para o negativo, ou seja, que não termina com.

Um exemplo simples, seria a busca, primeiramente, de Gustavo seguido por Dutra. Se existisse Gustavo ou Gustavo Outracoisa, ele não casaria. Ao contrário, o segundo exemplo somente casaria o Gustavo ou o Gustavo Outracoisa, porém não casaria o Gustavo Dutra:

/Gustavo(?= Dutra)/
/Gustavo(?! Dutra)

Vamos ver um exemplo mais funcional e complexo em python:

import re
print re.findall(r'\s?([^;]+);', 'Vim Editor; GVim Editor; Firefox Browser; Emacs Editor; Thunderbird Email;')
# output seria:
['Vim Editor', 'GVim Editor', 'Firefox Browser', 'Emacs Editor', 'Thunderbird Email']

Mas e se quisesse somente os editores da lista?

import re
print re.findall(r'\s?([^;]+ Editor);', 'Vim Editor; GVim Editor; Firefox Browser; Emacs Editor; Thunderbird Email;')
# output seria:
['Vim Editor', 'GVim Editor', 'Emacs Editor']

Mas e se eu quisesse todos MENOS os editores? É ai que entra o Lookahead, vamos pegar todos que não terminam com Editor.

import re
re.findall(r'\s?([^;]+ (?!Editor))', 'Vim Editor; GVim Editor; Firefox Browser; Emacs Editor; Thunderbird Email;')
# output seria:
['Firefox ', 'Thunderbird ']

Observem que o que casar com (?!Editor) não entra no resultado, para incluí-lo, seria necessário uma expressão regular um pouco mais complexa utilizando condicionais. Veremos isso depois!

Lookbehind

Lookbehind faz o mesmo que o lookahead, porém, como o próprio nome diz, não procura depois, mas sim antes, da string dita. (?<=…) para o positivo e (?

Vamos pegar um RT de um tweet do twitter.com. Como gosto de ser eclético, vou usar perl:

print "RT \@gustavotkg Testando ERs." =~ /(?< =@)gustavotkg/
# Output seria:
1

Essa expressão retorna 1 (ou seja, TRUE), caso exista algum gustavotkg precedido por uma @.

OBS: @ são escapadas porque representam variáveis do tipo array em perl.

print "Este é um RT \@gustavotkg Testando ERs." =~ /(?< !RT )\@gustavotkg/
# Output seria, vazio, pois o @gustavotkg é precedido por um RT
 
print "RT \@gustavotkg2 também estou testando ERs." =~ /(?
# Output seria:
RT @gustavotkg2 também estou testando ERs.

O \b significa borda de palavra (espaço, ponto final, exclamação, final de linha, etc). Como 2 não é uma borda de palavra, pois a expressão regular diz o seguinte: "Case com tudo que não começar com RT @gustavotkg seguido de uma borda de palavra".

Condicionais

Como se pode notar nos casos acima, os operadores de lookahead e lookbehind não colocam o valor casado junto ao resultado final. Para isso temos que verificar condicionalmente e adicionar manualmente o valor. A sintaxe é esta: (?(condicao)(caso verdadeiro)|(caso falso)).

Parece complicado, mas é bem simples, vamos começar com algo fácil utilizando php:

preg_match("/(?(?< =@)\w+|\w{2})/", "@testando", $r);
var_dump($r);
# Output seria:
array(1) {
  [0]=> string(8) "testando"
}
 
preg_match("/(?(?< =@)\w+|\w{2})/", "testando", $r);
var_dump($r);
# Output seria:
array(1) {
  [0]=> string(8) "te"
}

Notem o condicional: Se começar (lookbehind) com @, então quero que case toda a palavra que segue o @, caso contrário, quero apenas os dois primeiros caracteres. Fácil? Vamos complicar!

Lembra do exemplo mais acima do lookahead? Vou refrescar a memória:

import re
re.findall(r'\s?([^;]+ (?!Editor))', 'Vim Editor; GVim Editor; Firefox Browser; Emacs Editor; Thunderbird Email;')
# output seria:
['Firefox ', 'Thunderbird ']

Notem que ela não adicionar a categoria do Firefox nem do Thunderbird, pois o (?!) como supracitado, não é colocado junto no resultado final. Para adicioná-los, podemos usar o condicional.

preg_match_all("/(\w+ (?(?!Editor)\w+));/","Vim Editor; GVim Editor; Firefox Browser; Emacs Editor; Thunderbird Email;",$e);
var_dump($e);
// Output seria:
array(2) {
  [0]=>
  array(2) {
    [0]=>
    string(16) "Firefox Browser;"
    [1]=>
    string(18) "Thunderbird Email;"
  }
  [1]=>
  array(2) {
    [0]=>
    string(15) "Firefox Browser"
    [1]=>
    string(17) "Thunderbird Email"
  }
}

Ou seja, no segundo índice do array, que na verdade é o indice 1, consta o resultado pego. Veja que utilizamos o seguinte método: Se \w+ não for seguido de 'Editor' então pega o \w+, senão ignora pois não é para casar. Assim, se for Editor, ele nunca irá casar.

Dúvidas? Sugestões? Deixe um comentário!


Fonte: http://gustavodutra.com/post/348/lookahead-lookbehind-e-condicionais-em-expressoes-regulares/

0sem comentários ainda

Enviar um comentário

Os campos são obrigatórios.

Se você é um usuário registrado, pode se identificar e ser reconhecido automaticamente.