msdn05_capa.JPG

Clique aqui para ler todos os artigos desta edição

 

Expressão Regular com .NET

por Renato Guimarães

 

Quer reduzir dezenas de linhas de código por apenas uma string com alguns caracteres? Por exemplo, escreva uma função para validar e-mail, e verifique a quantidade de linhas para implementação. Cerca de 10 linhas, certo? Trabalhando com expressões regulares você pode fazer em uma linha o que não conseguiria fazer em dezenas de linhas de código.

Nesse artigo, você terá uma visão geral e aprenderá a base de expressão regular. Para isso, é preciso entender os significados dos meta-caracteres, aprender a escrever expressões e entender como tirar vantagem das classes do .NET Framework que suportam a expressão regular.

 

Entendendo uma expressão regular

Expressões Regulares são uma poderosa, flexível e eficiente linguagem para descrever e processar texto. O extensível padrão de combinação das expressões regulares permite analisar rapidamente grandes textos para procurar combinações específicas de caracteres, podendo extrair, editar, validar, formatar, substituir ou excluir substrings. Uma expressão regular é formada por dois tipos básicos de caracteres: literais e meta-caracteres. As mais simples são formadas por literais, por exemplo "a" ou por literais e meta-caracteres: "[-+]?([0-9]*\.)?[0-9]+([eE][-+]?[0-9]+)?”.

 

Existe um grupo de caracteres que é responsável pelo poder de processamento de uma expressão regular, ou seja, possuem algum significado especial para o Parser (máquina ou engine - Classes do .NET Framework), sendo:  $  ^ . { [ ( | ) ] }  *  +  ?  \ . O * (asterísco), + (sinal de adição) e ? (interrogação) são conhecidos como quantificadores porque afetam o número de vezes que uma expressão deve coincidir. Outra forma de especificar o número de combinações é implementada usando as chaves "{...}". A expressão que antecede esses quantificadores normalmente é um simples caracter, por exemplo, "a*", ou pode vir após os parênteses, por exemplo, "(....)*". Os parênteses são utilizados para agrupar expressões; e o “|”(pipe) é utilizado para indicar que a coincidência será com a expressão à esquerda ou à direita do pipe, por exemplo “a(bc|cd)e”, coincidirá com “abce”, “acde”. Veja exemplos de quantificadores na Tabela 1.

 

Expressão

Coincidência

Significado

maria

maria

Coincide somente o literal da expressão

ca*sa

csa, casa, caasa, etc

Nenhuma ou várias coincidências

ca+sa

casa, caasa, caaaasa, etc

Uma ou várias coincidências

ca?sa

csa ou casa

Nenhum ou uma coincidência

casa

caasa

Exatamente duas coincidências

ca{0,}sa

csa, casa, caasa, caaasa, etc

Nenhuma ou várias. Igual a *

ca{1,}sa

casa, caaasa, caaaasa, etc

Uma ou várias. {1,} é igual a +

ca{0,1}sa

csa ou casa

Nenhuma ou somente uma. Igual a ?

Tabela 1 - Exemplos de como utilizar os quantificadores *, + ,  ?, , {n, } e {n, m}

        

Classe de caracteres [...], O ponto "." e notações resumidas (atalhos)

 

O mais simples dos meta-caracteres é o ponto ".". Coincide com qualquer caracter, exceto os de retorno de carro(\r) e nova linha (\n).

 

Classe de caracter é um forma de você definir um conjunto ou intervalo possível de valores através de [...](colchetes). Sendo assim, "b[aei]d" coincidirá com 'bad", "bed" ou “bid”, mas não com "bod" ou "bud". Tudo que estiver entre colchetes é entendido como caracter único, então "[da]+" coincidirá com "d", "a", "da", "dad", "daaad", "ddaaddadaa" ou qualquer combinação entre d e a. Você pode definir um intervalo usando o hífen: "a[a-c]" coincidirá com "aa", "ab", "ac" mas não com "ad" ou qualquer letra fora do invervalo a-c. Dentro de uma mesma classe podemos definir vários intervalos e/ou caracteres singulares: "[A-Z a-z $ _ 0-9]" coincidirá com qualquer série de letras, maiúsculas ou minúsculas, cifrão, número ou sublinhado. Para negar uma classe de caracteres é preciso colocar um "^" após o "["(abre colchete) : "a[^a-z]" coincidirá com "a1", "a3", ou seja, um "a" seguido de um caracter que não seja uma letra minúscula, assim, não coincidirá, por exemplo, com “ab”. Para restringir uma expressão regular de modo que ela coincida somente com um exato padrão ou com um determinado padrão que apareça no começo ou no fim de um texto grande, você pode usar “^” e “$” para coincidir o começo e o fim do texto, respectivamente. A expressão “^a[^a-z]” coincide com qualquer palavra que comece por “a” não seguido de uma letra minúscula: “a1zzzz”, “a555zds”.   a expressão  “a[^a-z]$” coincide com qualquer palavra que termine por um “a” não seguido de letra uma minúscula: “a5a5a5a555za1”.

 

Outra forma de escrever uma classe de caracteres é através das notações resumidas (ou atalhos), que podem ser utilizadas individualmente ou dentro de outra classe de caracteres. Por exemplo, “\d” e “[\d]” são equivalentes a “[0-9]”. Observe que um atalho coincidirá com apenas um único caracter, da mesma forma que ocorre com as classes definidas com colchetes. Veja exemplos de atalhos na Tabela 2.

      

\d

Coincidirá com dígitos de 0-9

\D

Coincidirá com qualquer caracter que não seja \d. [^0-9]

\w

Coincidirá com caracteres para formar palavras. [a-z A-Z _ 0-9]

\W

Coincidirá com qualquer caracter que não seja \w. [^ a-z A-Z _ 0-9]

\s

Coincidirá com os caracteres de espaço. [\n \f \t \v]

\S

Coincidirá com os caracteres que não seja \s. [^\n \f \t \v]

Tabela 2 – Atalhos utilizados para representar classes de caracteres

 

 OBS: Alguns caracteres têm um significado especial numa classe de caracteres. Caso utilize como um literal, fique atento, pois precisam ser imediatamente precedidos por uma contra-barra. Exemplos: "\\" (contra-barra), "]" (fecha colchete), "^" (circunflexo) e o "-" (hífen"). Em C++ e C# você deve anteceder a  “\” (contra-barra) com outra contra-barra para que o compilador não entenda como um caracter de escape (atalho), por exemplo “\\d”, mas em C#, além da contra-barra você também pode colocar um @ antes da string. Usando o @ você está dizendo para o compilador não interpretar o que estiver dentro da string – String exp = @“\d” ou  String exp = “\\d”.

 

Exemplos de expressões regulares usando as classes do .NET

Agora com o .NET Framework temos uma poderosa implementação de expressões regulares que incorpora as mais populares características de outras implementações de expressão regular, tais como Perl 5.0 e awk.

 

O namespace System.Text.RegularExpressions é onde está centralizado o suporte a expressões regulares e tem como classe principal a Regex. Essa classe contém os métodos IsMatch (ver Listagem 1), Matches (ver Listagem 2), Split (ver Listagem 3) e Replace (ver Listagem 4) que você pode utilizar com uma expressão regular, tanto para pesquisar, formatar e substituir strings. Quando usada em pesquisas, a classe Regex pode retornar um simples objeto da classe Match ou uma MatchCollection. Além deste namespace, você também pode manipular expressões regulares no ASP.NET  com o controle web RegularExpressionValidator. É um excelente componente para validação  de dados digitados pelo usuário.

 

Vejamos algumas expressões para validar tipos de dados que fazem parte do dia a dia de qualquer aplicação, os códigos estão exemplificados através de aplicações console nas listagens 1 a 5. Caso tenha alguma dúvida em alguma expressão, veja o significado do caracter nas tabelas 1 e 2. Como a classe Regex tem alguns métodos estáticos, não é preciso instanciar um objeto antes de utilizar tais métodos, sendo ainda possível criar instâncias da classe Regex (Listagem 5).

 

Listagem 1. Uso do método IsMatch para verificar se uma string coincide com uma determinada expressão.

using System;

using System.Text.RegularExpressions;

public class Listagem1{

  [STAThread]

  static void Main(string[] args) {

  //Expressão para validar se é um número

  //com 5 dígitos

  String numCincoDigitos = @"^\d$";

  //O formato do cpf é 999.999.999-99.

  // \d \. \d \. \d \- \d

  //Limita a qtd de dígitos e usa o ponto

  //como um literal (contra-barra)

  // O ^ e $ indicam que a coincidência

  // pode ser no começo ou no fim da linha

  String formatoCPF = @"^\d\.\d\.\d\-\d$";

  Console.WriteLine("Digite um número com 5 dígitos: ");

  String entrada = Console.ReadLine();

  if (Regex.IsMatch(entrada, numCincoDigitos)){

    Console.WriteLine(entrada + " é válido!");

  }else{

            Console.WriteLine(entrada + " Inválido!");

  }

  Console.WriteLine("\n");

  Console.WriteLine("Digite CPF no formato válido: ");

  //Verifica se o cpf está no formato válido

  entrada = Console.ReadLine();

  if (Regex.IsMatch(entrada, formatoCPF)){

    Console.WriteLine("Cpf " + entrada + " válido!");

  }else{

    Console.WriteLine("Cpf " + entrada + " inválido!");

  }

  Console.Read();

 }

}

 

Listagem 2. Lista as coincidências usando o MatchCollection que é retornado pelo método Matches

using System;

using System.Text.RegularExpressions;

public class Listagem2{

  [STAThread]

  static void Main(string[] args){

  //Frase com espaço em branco

  String frase = "Faça, agora mesmo, a assinatura da sua revista MSDN";

  //Qualquer espaço não branco seguido por

  //espaço em branco

  String exp = @"(\S+)\s";

  //Pega as coincidências usando um MatchCollection e lista

  // as palavras que vem seguida de espaço em branco

  foreach (Match encontrada in Regex.Matches(frase, exp)){

            Console.WriteLine("Palavra: " +

        encontrada.Value);

  }

  //OBS: a string MSDN não será listada porque

  //não é seguida de espaço em branco.

  //Mude a expressão de forma que ela aceite a

  //última palavra da frase.

  Console.Read();

 }

}

 

Listagem 3. Use o método Split para dividir a string nos pontos onde coincide com a expressão

using System;

using System.Text.RegularExpressions;

public class Listagem3{

  [STAThread]

  static void Main(string[] args){

  //Frase com espaço em branco

  String frase = "Faça, agora mesmo, a assinatura da sua revista MSDN";

  //O método Split divide a string onde

  //coincidir com a expressão

  String exp = " |, |,";

  //O Split retorna um array de strings

  foreach (String substring in Regex.Split(frase, exp)){

            Console.WriteLine("Palavra: " + substring);

  }

  Console.Read();

 }

}

 

 

Listagem 4. Usa o método Replace para substituir caracteres que coincidem com a expressão

using System;

using System.Text.RegularExpressions;

public class Listagem4{

  [STAThread]

  static void Main(string[] args){

  //A expressão "^\w]" não aceita

  //caracteres inválidos

  Console.Write("Digite uma frase: ");

  Console.WriteLine("Resultado: " +

    Regex.Replace(Console.ReadLine(), @"[^\w]", ""));

  Console.Read();

 }

}

 

Listagem 5. Cria instâncias da classe Regex

using System;

using System.Text.RegularExpressions;

public class Listagem5{

  [STAThread]

  static void Main(string[] args){

  //Valida email

  Regex regExEmail = new Regex(@"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$");

  //Valida uma hora no formato HH:MM

  Regex regExHora =

new Regex("^([0-1][0-9]|2[0-3]):[0-5][0-9]$");

  //Valida se a string possui apóstrofo

  Regex regExAspa = new Regex("^[^']*$");

  //Valida o tamanho da string até 16 caracteres

  Regex regExTamanhoString =

        new Regex("^(.|\n){0,16}$");

  //Valida CEP

  Regex regExCEP =

        new Regex(@"^\d\.\d$");

  //Valida o caminho do arquivo doc, xls ou exe

  Regex regExCaminhoArquivo =

        new Regex(@"([a-zA-Z]:(\\w+)*\\[a-zA-Z0_9]+)?.[doc|exe|xls]");

  //O email renato#kbca@msn.com é inválido

  Console.WriteLine("E-mail renatokbca@msn.com: " +

    regExEmail.IsMatch("renatokbca@msn.com"));

  Console.WriteLine("CEP 51340-221: " +

    regExCEP.IsMatch("51340.221"));

  Console.WriteLine("Hora 23:59 " +

    regExHora.IsMatch("23:59"));

  Console.WriteLine("Caminho c:\\msdnmagazine.doc " +

    regExCaminhoArquivo.IsMatch("c:\\msdnmagazine.doc"));

  Console.Read();

 }

}

 

Conclusão

Com os exemplos mostrados neste artigo você percebeu quão poderosa e flexível é a linguagem. Crie suas expressões e evite perder tempo com código que não seja a regra de negócio. Para seu aprimoramento e desenvolvimento, recomendo pesquisar os outros métodos das classes Regex e no namespace System.Text.RegularExpression.

 

Referências:

 

RegexDesigner.NET é uma excelente aplicação windows escrita em C# para validação de expressão regular.

http://www.sellsbrothers.com/tools/#regexd

 

Site com vários exemplos de expressão regular e opção para validar expressão

http://www.regexlib.com

 

 

OLHO: Trabalhando com expressões regulares você pode fazer em uma linha o que não conseguiria fazer em dezenas de linhas de código.