Expressões Regulares
Por Francisco Demontiê dos Santos Junior
(demontie@dsc.ufcg.edu.br)
O PETNews passou por uma reformulação, tanto na sua aparência, quanto no seu conteúdo. Entre as novidades, está a Coluna Java, cujo objetivo é mostrar tópicos de interesse, e pouco abordados durante a nossa graduação, dessa linguagem de programação. Como primeiro tópico, tem-se as Expressões Regulares, mostrando como e por que usar.

Uma expressão regular (ER) nada mais é do que um método formal para especificar padrões de cadeias de caracteres (palavras), de forma concisa e flexível. Pode-se utilizar as expressões regulares, dentre outras aplicações, na definição de linguagens, na construção de autômatos e na geração de analisadores léxicos (parte integrante de um compilador). Nesta matéria, serão tratadas as expressões regulares com o objetivo de verificar (casar) padrões de texto.

Suponha que estamos desenvolvendo um software para uma clínica de odontologia e queremos implementar o módulo de cadastro de clientes. A fim de construir um software robusto, verificaremos se os dados fornecidos pelo usuário do sistema seguem os padrões corretos. Uma das verificações que desejamos fazer é “o nome do cliente é composto apenas por letras e espaços em branco”. Uma abordagem válida é iterar sobre todos os caracteres da entrada fornecida e testar um a um. O código poderia ser esse:

1. public boolean verificaNome(String nome) {
2.     for (Character c : nome.toCharArray()) {
3.         if (!Character.isLetter(c) && !Character.isSpaceChar(c)) {
4.             return false;
5.         }
7.     }
8.     return true;
9. }

Fácil, não? E se começarem a surgir outros padrões para os quais precisamos verificar outras propriedades? O nosso código verificador começará a aumentar e a se tornar mais complicado. Tendo em vista esse problema, por que não usar expressões regulares para definir esses padrões? Para isso, vamos entender a gramática das ERs e como usá-las em Java.

Para entender a gramática das ERs em Java vamos, primeiramente, conhecer alguns dos caracteres especiais mais usados, como: [\^]?*+-&&.

Usamos os colchetes para indicar que a palavra a ser validada deve conter um dos elementos do conjunto especificado, ou seja, a expressão regular [abc] valida as palavras “a”, “b” e “c”. Analogamente, podemos definir a seguinte ER: alun[ao] que valida as palavras “aluna” e “aluno”. Se o conjunto definido possuir uma sequência lógica, podemos simplesmente especificar o primeiro e o último elementos da sequência, separando-os por um hífen. Ou seja, a expressão regular [abc] pode ser representada por [a-c].

O símbolo "^" representa a função de exclusão, ou seja, podemos definir um conjunto de caracteres que não deve estar na palavra. Por exemplo, a ER [^abc] reconhece palavras que não sejam "a", "b" ou "c". O símbolo "&&" representa a função de interseção entre duas expressões regulares. Com esses caracteres especiais, já podemos definir ERs como: [a-e&&[aeiou]] (interseção das letras do alfabeto de "a" até "e" com as vogais) e [a-e&&[^aeiou]] (as letras do alfabeto de "a" até "e" excluindo as vogais, resultando em "b", "c" e "d").

A seguir, outros caracteres especiais.

  • "." (ponto): qualquer caractere. Ex.: a expressão regular a.b valida qualquer cadeia de três caracteres que inicie com "a" e termine com "b";
  • "*": representa o Fechamento de Kleene, que, basicamente, indica zero ou mais ocorrências da expressão regular. Ex.: a expressão regular a*b valida as palavras que tenham qualquer quantidade de "a" (inclusive nenhuma ocorrência) e terminem em "b";
  • "+": representa o Fechamento Positivo de Kleene, que, basicamente, indica uma ou mais ocorrências da expressão regular. Ex.: de forma análoga ao exemplo anterior, a ER a+b valida as palavras que tenham uma ou mais ocorrências de "a" e terminem em "b";
  • "?": zero ou uma ocorrência.
  • "\" : esse caractere pode ser usado antes dos caracteres especiais para que eles possam ser lidos como caracteres comuns. Ex.: a expressão regular [0-9]\+[0-9] representa uma soma entre dois números de um dígito, validando palavras como "2+3". Além disso, pode-se usar a contrabarra antes de uma classe de caracteres pré definidos conforme descrito a seguir.
    • \d : um dígito;
    • \D : algo que não seja um dígito;
    • \s : um espaço em branco;
    • \S : algo que não seja um espaço em branco;
    • \w : qualquer letra, dígito, ou sublinha ( _ );
    • \W : algo que não seja letra, dígito ou sublinha.

Para mais informações sobre caracteres especiais suportados pela API de Java, veja a documentação.

Voltemos agora ao nosso problema inicial. Queremos definir uma expressão regular que represente uma classe de cadeias de caracteres compostas apenas por letras e espaços em branco. Com os conhecimentos adquiridos sobre a gramática, podemos facilmente construir a seguinte ER: [A-Za-z\s]+. Como exercício, tente construir outra ER, mais restrita (não aceitando vários espaços seguidos, por exemplo), que resolva o mesmo problema.

Agora que temos a nossa expressão regular, estamos interessados em verificar se uma String de entrada casa com o padrão definido. Para isso, podemos usar o seguinte trecho de código:

1.  public boolean verificaNome(String nome) {
2.      Pattern padrao = Pattern.compile("[A-Za-z\\s]+");  
3.      Matcher pesquisa = padrao.matcher(nome);   
4.  	  
5.      if (pesquisa.matches()) {  
6.          return true;    
7.      }  
8.      else {  
9.          return false;  
10.     }
11. }

Note que, em Java, usamos "\\" na String, ao invés de "\", para que o caractere especial seja reconhecido (isso ocorre pelo fato de "\" ser usado para caracteres de tabulação, como "\n").

A função de verificação acima pode conter apenas uma linha de código, caso seja utilizada a função estática matches(String expRegular, CharSequence entrada) da classe Pattern, como mostrado a seguir.

1. public boolean verificaNome(String nome) {
2.     return Pattern.matches("[A-Za-z\\s]+", nome);
3. }

Envie-nos dúvidas, correções e/ou sugestões de temas que você deseja ver nas próximas edições.


Fontes:

- http://download.oracle.com/javase/1.4.2/docs/api/java/util/regex/Pattern.html. Acesso em 10/03/2011.

- http://javafree.uol.com.br/artigo/5090/java.sun.com/docs/books/tutorial. Acesso em 10/03/2011.