Esse artigo faz parte da revista Java Magazine edição 04. Clique aqui para ler todos os artigos desta edição

Clique aqui para ler essa revista em PDF.imagem_pdf.jpg

Expressões Regulares no J2SE 1.4

Processamento de texto ao estilo Perl

As nova API java.util.regex incorpora recursos clássicos de manipulação de expressões regulares com simplicidade e desempenho

Expressões regulares são comumente utilizadas para procurar ou alterar fragmentos de texto em documentos de conteúdo textual. Tais fragmentos (sequências de caracteres) são identificados através de regras de formação, ou padrões, que compõem as expressões regulares.

As expressões regulares são disponibilizadas ao usuário através de ferramentas de linha de comando, tais como grep, sed, ou awk, típicas em ambientes Unix, ou através de linguagens de programação, tais como Perl, C, Python ou Java. Destas linguagens, apenas Perl suporta expressões regulares de forma integrada. As demais, as suportam através de APIs (bibliotecas de funções/classes).

Na prática, a sintaxe das expressões regulares varia de uma ferramenta ou linguagem para outra, o que reflete a inexistência de um padrão na indústria. Apesar disso, uma sintaxe em particular tornou-se dominante: a da linguagem Perl, na versão 5. Esta sintaxe foi adotada, na maior parte, por várias linguagens e APIs modernas, incluindo a nova API padrão do J2SE 1.4.

APIs

O pacote java.util.regex, novo no J2SE 1.4, define a API padrão para expressões regulares. Além da adição deste pacote, a classe String ganhou métodos adicionais que aceitam como argumento uma expressão regular (por exemplo, o método split). Estes métodos, contudo, são apenas para conveniência. Tudo o que eles fazem pode também ser feito através das classes específicas para expressões regulares, definidas naquele pacote.

Existem também outras APIs disponíveis para a plataforma Java, tais como as do projeto Jakarta da organização Apache (veja links). A API do J2SE 1.4 é considerada uma das melhores, tanto em capacidade quanto em desempenho. Assim sendo, neste artigo nos limitamos a esta API, e à sua sintaxe de expressões regulares. O código de exemplo no artigo foi testado com o J2SDK 1.4.1, da Sun.

Antes do J2SE 1.4, as classes java.util.StringTokenizer e java.io.StreamTokenizer eram o que havia de melhor quando se precisava ler e interpretar texto (salvo APIs fora do padrão J2SE). A nova API para expressões regulares é uma alternativa mais poderosa, capaz de simplificar a resolução dos mesmos problemas, bem como outros significativamente mais complexos.

Aplicações

Expressões regulares vêm sendo utilizadas há décadas. Seus usos vão dos mais básicos (como no comando DOS “dir *.txt”), aos mais avançados (por exemplo, em uma ferramenta que procura possíveis erros de digitação num documento, tais como palavras duplicadas). Em geral, expressões regulares constituem uma linguagem especializada que permite resolver problemas no processamento de informações representadas em forma textual. Alguns problemas envolvem documentos narrativos, como no caso das palavras duplicadas; outros envolvem dados estruturados, como no exemplo que veremos a seguir.

Nota: é interessante observar que tecnologias XML, em particular XPath, tornam geralmente desnecessário o uso de expressões regulares no processamento de documentos XML. Porém, a necessidade de processar documentos textuais em formatos não-XML é muito comum.

Sintaxe e semântica

Sintaticamente, uma expressão regular é uma sequência de caracteres arbitrários. Certos caracteres e combinações de caracteres têm significado especial. Semanticamente, cada expressão regular representa um conjunto de possíveis fragmentos de texto. Por exemplo, uma palavra ou número, uma sequência de caracteres com um certo prefixo ou sufixo, uma palavra seguida de um número ou de outra palavra, um certo caractere no final da linha, e assim por diante.

Vejamos alguns exemplos concretos (aqui e no resto do artigo, escrevemos uma expressão regular como uma sequência de caracteres entre aspas duplas):

·         “carro” – representa uma única palavra, “carro”;

·         “[0-9]+” – representa um número inteiro composto de um ou mais dígitos de 0 a 9;

·         “A_?\d+” – representa um fragmento de texto que começa com a letra “A”, seguido opcionalmente pelo caractere sublinhado “_”, e terminando com um número inteiro.

No primeiro exemplo, somente caracteres literais foram utilizados. Nos demais, além de caracteres literais, foram usados alguns caracteres especiais, ou meta-caracteres. Mais adiante descreveremos o significado destes meta-caracteres.

Dado um texto de entrada e uma expressão regular ER, uma ferramenta ou linguagem de programação com suporte a expressões regulares é capaz de procurar por correspondências (matches) à expressão ER dentro do texto. Uma correspondência, quando encontrada, inclui a sequência de caracteres no texto de entrada que foi reconhecida pela expressão regular, e as posições do primeiro e último caracteres reconhecidos.

Uma vez encontrada uma correspondência, o programa que está processando o texto de entrada normalmente realiza uma ação em resposta, que depende do propósito do programa. Por exemplo, o programa poderia simplesmente imprimir as linhas nas quais uma correspondência foi encontrada, ou poderia registrar a informação obtida da correspondência num banco de dados, e assim por diante. Em geral, é também possível substituir o fragmento reconhecido, no texto de entrada, por algum outro fragmento de texto qualquer.

Exemplo prático

Como um exemplo não trivial, vamos apresentar uma classe que lê um arquivo texto contendo dados estruturados numa tabela (com linhas e colunas), e produz um documento XML com os mesmos dados. (Numa aplicação real, isto provavelmente seria um passo intermediário no processamento do arquivo original. O resultado final poderia ser, digamos, um script SQL com comandos insert, ou uma página HTML).

Os dados em cada linha do arquivo incluem códigos alfa-numéricos, números inteiros e reais, e intervalos numéricos abertos e fechados. A Listagem 1 é um desses arquivos texto, contendo dados para cada caso. Para este arquivo, a classe TextoParaXml na Listagem 3, irá produzir o texto XML mostrado na Listagem 2.

No restante do artigo, explicamos os recursos da API para expressões regulares de J2SE 1.4 que são utilizados neste exemplo (Listagem 3).

 

Caracteres especiais

Uma expressão regular, na sintaxe suportada por java.util.regex, pode incluir como caracteres literais todos os definidos pelo padrão Unicode. (O padrão ASCII define os números associados a um conjunto de 128 caracteres apropriados à lingua inglesa; Unicode faz o mesmo para estes e milhares de outros caracteres, cobrindo praticamente todas as línguas existentes.)

Nesta API, os seguintes caracteres são especiais (meta-caracteres): ()[]{}\|.?*+^$

Quando o fragmento procurado no texto de entrada pode incluir um destes meta-caracteres, é preciso usar o meta-caractere “\” (barra reversa) na expressão regular, para remover o significado especial. Por exemplo, para encontrar correspondências contendo parênteses, usa-se “\(” e “\)” na expressão regular. Isto, entretanto, conflita com o significado especial da barra reversa em Strings literais em código Java, como em “\n”, ou no string “ab\”cd\\ef”, que contém uma aspa dupla e uma barra reversa. Assim, quando uma expressão regular aparece numa string literal em código Java, é preciso preceder cada barra reversa por outra barra reversa. Por exemplo, a expressão “\([xyz]\)” seria escrita como “\\([xyz]\\)” em código Java.

Elementos da API

O pacote java.util.regex possui apenas três classes, sendo uma delas uma classe de exceção. A classe Pattern representa um padrão (expressão regular) “compilado”, que é armazenado internamente numa estrutura de dados otimizada. Instâncias desta classe são imutáveis. Um objeto da classe Matcher tem a habilidade de encontrar correspondências num texto de entrada para uma dada instância de Pattern. O estado de um Matcher reflete o resultado da última operação de busca por uma correspondência no texto de entrada. ...

Quer ler esse conteúdo completo? Tenha acesso completo