Expressões Regulares no dia a dia

Este artigo é destinado a pessoas que querem saber mais sobre expressões regulares. No dia a dia é bastante útil para fazer buscas avançadas e alterações em lote em editores de texto que suportam expressões regulares (como notepad++, sublime text, eclipse etc). Em programação é muito usado para fazer validação de entradas de dados.

Para entender este artigo, não é necessário nenhum pré-requisito. Vamos lá..

“Uma expressão regular provê uma forma concisa e flexível de identificar cadeias de caracteres de interesse, como caracteres particulares, palavras ou padrões de caracteres. ” [wikipedia]

Está complicado, vamos para algo mais prático..

xkcd208

Cenários reais

Considere os seguintes cenários obtidos de casos reais e veremos como expressões regulares podem nos ajudar a solucioná-los.

  1. Você precisa encontrar um email no meio de um texto de 200MB.
  2. Você necessita modificar um arquivo de texto com o padrão de data mês/dia/ano para dia-mês-ano.
  3. Você tem um arquivo csv e quer alterar o valor da 5ª coluna por “don’t touch me”
  4. Você recebeu um arquivo posicional de 10.000 linhas onde todas as linhas deveriam ter exatamente 30 caracteres, porém algumas linhas têm menos caracteres. Você precisa encontrar estas linhas. O problema é que muitas delas acabam com espaço o que torna difícil identificar visualmente as linhas incorretas.

Ferramenta

Para facilitar, vamos usar uma ferramenta online http://www.regexr.com . Entra lá para fazermos juntos mas volte hein. Estou esperando.

Expressão

Pronto, vamos começar!

Expressão ou padrão é um conjunto de caracteres que representa o texto. Em geral a expressão pode ser a própria palavra procurada.

Por exemplo:

Texto: “Laranja, Banana, Maçã”
Procurando pelo padrão: “Banana”

Encontra a palavra “Banana” no texto.

a1

“Tá, mas não vi vantagem nenhuma”. A vantagem é que esta não é a única expressão para encontrar a palavra Banana. Quaisquer destas expressões a seguir permite encontrar esta palavra neste texto: 1- ”B\w\w\w\w\w”, 2- “Ba(na){2}”, 3- ”[Bna]{6}”, 4- ”[^\s]{4}na”.

Explicações de como encontrar a Banana:

1- \w = representa um caractere alfanumérico.

então a expressão B\w\w\w\w\w, representa todas a palavras que começam com B seguido de 5 caracteres alfanuméricos

b1

 

2- {} = representa a quantidade de ocorrências. Assim a expressão Ba(na){2} representa todas as palavras que começam com “Ba” seguido de dois “na” (por enquanto ignore os parênteses)

b2

 

3- [] = representa uma ocorrência de qualquer caractere contido na lista. Então a expressão [Bna]{6} representa todas as palavras de 6 caracteres formado por quaisquer das letras “B”, “n” ou “a”.

b3

 

4- ^ = dentro de um [] representa a negação e “\s” representa espaço, tabulação ou quebra de linha. Então a expressão “[^\s]{4}na” representa todas as palavras que tem os 4 primeiros caracteres não espaço, tabulação ou quebra de linha seguido de um “na”

b4

Obs: como alguns grupos de caracteres começam com “\” como por exemplo “\s”, se precisar procurar pelo texto “\”, você precisará usar o caracter de escape ”\” assim: “\\”.

Importante: Ao escrever uma expressão deve-se avaliar o contexto onde esta expressão será aplicada. Se o domínio do contexto for ilimitado, a expressão deve ser mais restritiva.

Para saber mais sobre expressões ou padrões procure por “regular expression” ou “regex” no Google e/ou veja algumas das referências abaixo:

http://en.wikipedia.org/wiki/Regular_expression

https://msdn.microsoft.com/en-us/library/az24scfc(v=vs.110).aspx

Ou no próprio site do http://www.regexr.com/ em cheatsheet.

Substituição e Grupo

Agora que sabemos como encontrar uma “Banana” num texto, vamos trocar “Banana” por “Banana nanica”.

Na ferramenta Regexr basta colocar o texto a substituir:

Expressão: [^\s]{4}na
Texto: Laranja, Banana, Maçã
Substituição: Banana nanica

c1

É.. ok.. mas é ruim escrever o texto a ser substituído. Seria legal se aproveitássemos o texto usado na expressão. Nós podemos aproveitar usando grupos de captura.

Grupos de captura são definidos por expressões entre parenteses e seu índice é determinado pela posição do grupo na expressão.

Por exemplo: Definindo a expressão: (Ba)(na)(na) na frase, temos que o “Ba” é o grupo 1, o primeiro “na” é grupo 2 e o segundo “na” é o grupo 3.

Vamos testar trocando “Banana” por “Bacana”. Para isso, basta modificar o grupo 2 pela sílaba “ca”. Assim podemos usar na expressão: “(Ba)(na)(na)” e na substituição o o seguinte texto: “$1ca$3”

Expressão: (Ba)(na)(na)
Texto: Laranja, Banana, Maçã
Substituição: $1ca$3

c2

Uau!! Bacana!

Resolvendo os cenários reais

Ok, mas eu não acho bananas bacanas então vamos voltar para os casos mencionados no início:

1- Você precisa encontrar um email no meio de um texto de 200MB.

Solução proposta: Procurar pelo padrão de email: nome, @, dominio , ponto e sufixo.

Exemplo: sobrenome.nome @ www.matera.com . br
Expressão: [\w\._]+ @ [a-zA-Z_\.]+ \. [a-zA-Z]{2,3}

Obs1: Neste exemplo usamos o caractere de escape “\” antes do ponto. Isto porque o caractere “.” significa qualquer caractere.
Obs2: O simbolo “+” representa cadeias de 1 ou mais ocorrências da expressão precedente. Tem o mesmo significado de  “{1,}”.
Obs3: a-z significa todos os caracteres de a a z, assim como A-Z significa todos os caracteres de A a Z.

Expressão: [\w\._]+@[a-zA-Z_\.]+\.[a-zA-Z]{2,3}
Texto:
nome: Eu
email: sobrenome.nome@www.matera.com.br.
endereço: bla bla bla… @ bla

d1

 

2- Você necessita modificar um arquivo de texto com o padrão de data mês/dia/ano para dia-mês-ano.

Solução proposta:

Procurar pela data, expressão composta por (2 dígitos), /, (2 dígitos), /, (4 dígitos) e substituir usando os grupos de captura:

Exemplo: 04 / 14 / 2014
Expressão: (\d{2}) / (\d{2}) / (\d{4})
Substituição: $2 $1 $3


Expressão: (\d{2})/(\d{2})/(\d{4})
Texto: data 04/14/2014
Substituição: $2-$1-$3

d2

3- Você tem um arquivo csv e quer alterar o valor da 5ª coluna por “don’t touch me”

Solução proposta: Procurar as 4 primeiras colunas e deixar no grupo 1. A coluna é determinada pela sequência de caracteres diferente de “;” seguido de “;”. Procurar a 5 coluna e deixar no grupo 2. Manter o grupo 1 e trocar o restante pela palavra desejada.

Exemplo: Lorem ; ipsum ; dolor ; sit ; amet ;
Expressão: ^ (( [^;]* ; ){4} ) ([^;]*) ;
Substituição: $1 don’t touch me ;

Obs1: O símbolo “^” no inicio da expressão significa início do texto
Obs2: O símbolo “*” significa 0 ou mais ocorrências da expressão precedente. Tem o mesmo significado de: “{0,}”.
Obs3: Selecione flags > multiline para avaliar cada linha separadamente

Expressão: ^(([^;]*;){4})([^;]*);

Texto:
asd;zcxv;qer;3dsfas;;zxcv;
vidsjf;djfslaf;ereiu;weui;vzxv;sdfsd;
1;2;3;4;5;6;

Substituição: $1don’t touch me;

d3

4- Você recebeu um arquivo posicional de 10.000 linhas onde todas as linhas deveriam ter exatamente 30 caracteres, porém algumas linhas têm menos caracteres. Você precisa encontrar estas linhas. O problema é que muitas delas acabam com espaço o que torna difícil identificar visualmente as linhas incorretas.

Solução proposta:

Procurar pela linha que do início ao fim tem de 0 a 29 caracteres quaisquer:

Exemplo: 12345678911234567892123456789
Expressão: ^ .{0,29} $

Obs1: O símbolo “$” significa fim do texto
Obs2: O símbolo “.” significa qualquer caractere.
Obs3: As últimas duas linhas do texto de exemplo abaixo têm espaços no final completando 30 caracteres.

Expressão: ^.{0,29}$

Texto:
123456789112345678921234567893
12345678911234567892123456789
1234567891123456789212345678  
afds  sdfsd  dsaf  asdfs      

d4

Viva! Não salvamos o mundo, não achamos assassinos, mas sabemos Expressões Regulares e isso pode salvar muito tempo de nossas vidas!

Conclusão

Vimos que expressão regular pode ser usado facilmente (ou não) para encontrar palavras  ou ser usada em edição em lote de um arquivo.

Esta ferramenta é muito poderosa, porém se for usar em código compartilhado tenha cuidado pois a manutenção muitas vezes se torna difícil ou até mesmo impossível.

E para terminar uma frase de Jamie Zawinski:

“Algumas pessoas, em frente a um problema, pensam “Já sei, vou usar expressões regulares”. Agora eles têm dois problemas.” ~ Jamie Zawinski

Será?

Referências

http://www.regexr.com/

http://en.wikipedia.org/wiki/Regular_expression

http://www.w3schools.com/jsref/jsref_obj_regexp.asp

https://msdn.microsoft.com/en-us/library/az24scfc(v=vs.110).aspx

http://www.tirinhas.com/xkcd.php?tira=208

https://xkcd.com/208/

 http://regex.info/blog/2006-09-15/247

Por FÁBIO MARCOS EIJI OKUDA

Postado em: 01 de junho de 2015

Confira outros artigos do nosso blog

REST não é JSON

21 de agosto de 2017

Bruno Sofiato

[Webinar] Profile de aplicações Java com Oracle Mission Control e Flight Recorder

24 de julho de 2017

Danival Calegari

Criando Mocks de serviços REST com SoapUI

27 de junho de 2017

Monise Costa

JavaScript 6: diferença entre var, let e const

09 de maio de 2017

Otávio Felipe do Prado

Deixe seu comentário