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!
0sem comentários ainda