Regex em C#: como utilizar expressões regulares

Regex em C#: como utilizar expressões regulares

No dia a dia, sempre que possível, procuramos estabelecer alguns padrões para facilitar o entendimento e organização de informações, algo que fazemos naturalmente, afinal estamos sempre buscando uma forma de otimizar a nossa rotina.

Dentro da área de Programação, também há essa preocupação em melhorar e otimizar informações, vide os padrões de programação, estruturas de dados e algoritmos. Mas, na rotina de uma pessoa programadora, em algum momento ela irá se deparar com a necessidade de trabalhar com cadeias de caracteres e buscar identificar padrões para extrair informações ou validar algum tipo de dado.

Neste contexto, hoje temos as chamadas expressões regulares, ou o termo abreviado do inglês, regex. Mas o que são? Onde vivem? De que se alimentam? Consigo usar com .NET? Neste artigo vamos conversar um pouco sobre elas. Vamos à leitura!

O que é uma expressão regular?

Vamos a algumas definições:

De acordo com Alfredo Lotar, autor do livro “Como programar com ASP.NET e C#", uma expressão regular define combinações de caracteres que podemos usar para representar partes de uma string.

Já para Cláudio Ralha, autor do livro Produtividade com C# da Casa do Código:

Expressões regulares são ferramentas para executar com pouco código tarefas complexas, como localizar e remover várias ocorrências de sequências de caracteres dentro do texto, validar dados informados pelos usuários que estão em um formato específico.

Então, podemos concluir que uma regex vai definir uma forma de identificar padrões em cadeias de caracteres (strings) e que podemos usá-la para validações de dados.

Um pouco de história

A história das expressões regulares está intimamente ligada à teoria da computação, pois ela faz parte da teoria dos automatos e linguagens formais. As regex foram desenvolvidas nos estudos do matemático americano Stephen Cole Kleene, que a princípio chamava de álgebra de conjuntos regulares.

Os trabalhos de Kleene foram a base para a criação de algoritmos de busca usados na computação. Hoje, aplicamos as regex em editores de texto, em funções de busca e substituição, e nas linguagens de programação como forma de validação de formatos de textos. Por exemplo: quando precisamos validar o formato do campo e-mail de um formulário, podemos usar: /^[a-z0-9.][email protected][a-z0-9]+\.[a-z]+\.([a-z]+)?$/i;.

Então, em resumo, as regex podem ser aplicadas em situações de:

  • Mecanismos de validação de dados de formulários;
  • Encontrar um texto específico em uma string;
  • Representação de padrões. Por exemplo: os números em um CPF.

Ok, mas como funcionam as regex?

Quando usamos regex, a busca pelo caractere, string ou padrão de texto é feita da esquerda para a direita, da mesma forma como lemos um texto (pelo menos de acordo com a leitura ocidental). Essa busca pode ser feita em uma única linha ou em várias delas, além de poder diferenciar letras maiúsculas e minúsculas e inclusive ignorar espaços em branco.

Vamos acompanhar um exemplo de uma regex para validação de um CPF:

/^[0-9]{3}.?[0-9]{3}.?[0-9]{3}-?[0-9]{2}/

Na definição de uma regex podemos utilizar dois tipos de caracteres: os literais, usados normalmente em strings, e os metacaracteres, que fazem com que a regex possa processar e manipular informações. Compilamos alguns metacaracteres na tabela a seguir:

MetaDescrição
*Indica nenhuma ou várias ocorrências de um caractere
+Repete pelo menos uma vez um caractere. Exemplo: /a+/
^Indica que a pesquisa será feita no início do bloco ou regra
$Sinaliza que a pesquisa será feita no fim do bloco ou regra
?Usado para declarar um caractere como opcional
|Atua como o operador lógico ou
Usado para indicar um caractere
()Usado para agrupar uma sequência. Exemplo: /(abc)/

Além deles, as regex também permitem trabalhar com agrupamentos, que podem nos ajudar a criar sub-expressões. Para definir grupos, podemos utilizar (). Na sequência, listamos alguns:

GruposDescrição
[aeiou]Considera combinações de vogais
{n}Indica a quantidade de números retornados
[a-zA-Z_0-9]Considera letras maiúsculas e minúsculas e números
{n,m}Indica um intervalo

Vale a pena destacar que criar uma sentença regex fazendo uso dos símbolos e metacaracteres disponíveis pode ser extremamente trabalhoso. Dividir uma expressão em partes pode nos ajudar, no melhor estilo “dividir para conquistar”.

Por exemplo: se quisermos selecionar todas as letras e números de um texto, podemos escrever uma expressão que escolha os números [0-9], depois escrever a que seleciona as letras [a-zA-Z]. Por fim, juntamos as partes da expressão como [0-9][a-zA-Z].

Até aqui vimos que dentre as vantagens na utilização das regex temos a flexibilidade, a performance e a facilidade de uso. Mas após entender a teoria, como podemos fazer o uso das regex com o C#? Para isso precisamos utilizar uma classe Regex - e é isso que vamos conhecer no próximo tópico!

A classe Regex

No .NET a principal classe para trabalhar com regex é a de mesmo nome, Regex, que se encontra no namespace System.Text.RegularExpressions. Ela possui uma série de métodos estáticos que nos possibilitam trabalhar com expressões regulares. Por exemplo, se quisermos validar se o valor informado por um usuário é composto somente por números, podemos fazer o seguinte:

using System.Text.RegularExpressions;

Console.Write("Informe um valor:  ");
var caracteres = Console.ReadLine();

bool ok = Regex.IsMatch(caracteres, "^[0-9]+$");
if (!ok)
{
    Console.WriteLine("O valor informado não é um numérico válido.");
}
else
{
    Console.WriteLine("O valor informado é válido.");
}

Executando o código acima e informando 14589AC, temos como saída o que é mostrado na imagem abaixo:

Recorte da tela do console onde o usuário informa a string `14589AC` e é mostrado como resultado a mensagem `O valor informado não é um numérico válido`.

Podemos ainda criar um objeto do tipo Regex que recebe em seu construtor um caractere ou uma expressão composta pelos metacaracteres. Também é possível informar um segundo parâmetro definindo como fazer essa busca.

Imagine que você precisa validar um CPF de usuário. Ao invés de criar todo um algoritmo, por que não usar uma regex? Observe como poderia ser implementado:

Console.Write("Informe um cpf para validação: ");
var cpf = Console.ReadLine();

Regex regex = new Regex(@"([0-9]{4}[-]?[0-9]{2})|([0-9]{3}[\.]?[0-9]{3}[\.]?[0-9]{3}[-]?[0-9]{2})",RegexOptions.IgnoreCase);
var combinou = regex.Match(cpf);
if (combinou.Success)
{
    Console.WriteLine("CPF no formato válido.");
}
else
{
    Console.WriteLine("CPF inválido.");
}

Executando o código acima, o usuário informa um CPF contendo somente números ou com a máscara com pontos, criado um objeto da classe Regex que recebe como parâmetro uma expressão para CPF e uma enumeração com o valor de IgnoreCase, que diferencia maiúscula de minúscula.

Ao executar o método .Match() do objeto, validamos o CPF com a regex definida na criação do objeto. Para isso, é importante trabalharmos o retorno criando um objeto do tipo Match.

Se quisermos validar, por exemplo, 000.869.630-66, ao executarmos teremos como saída no terminal o seguinte:

Recorte da tela do console onde o usuário informa o CPF `000.869.630-66` e é mostrado como resultado a mensagem `CPF no formato válido.`

Ok, mas e se o CPF para validação não estiver com a máscara de CPF? Por exemplo, 99156503024. E aí?

Recorte da tela do console onde o usuário informa a o CPF `99156503024` e é mostrado como resultado a mensagem `CPF no formato válido.`

Abaixo apresentamos algumas opções da enumeração RegexOptions que podemos usar quando criamos nossos objetos regex:

ValorDescrição
IgnoreCasePara ignorar maiúsculas ou minúsculas
CultureInvariantNão considerar idiomas
MultilineRealizar a pesquisa em múltiplas linhas
SingleLineRealizar a pesquisa em uma única linha
RightToLeftRealizar a pesquisa da direita para esquerda
IgnorePatternWhitespaceIgnorar padrões com espaço em branco

Usando o .IsMatch()

Com o IsMatch podemos validar se um valor informado combina com a expressão regular definida. O retorno do método é um booleano e recebe como parâmetro uma string. Usando o mesmo exemplo do CPF, temos:

Console.Write("Informe um cpf para validação: ");
var cpf = Console.ReadLine();

Regex regex = new Regex(@"([0-9]{4}[-]?[0-9]{2})|([0-9]{3}[\.]?[0-9]{3}[\.]?[0-9]{3}[-]?[0-9]{2})", RegexOptions.IgnorePatternWhitespace);
if (regex.IsMatch(cpf))
{
    Console.WriteLine("CPF válido.");
}
else
{
    Console.WriteLine("CPF inválido.");
}

Usando o .Match()

Este método pode ser usado para buscar uma string ou expressão regex definida na classe. Por exemplo:

var busca = "Mergulhando em tecnologia com a Alura.";
Regex regex = new Regex("Alura",RegexOptions.IgnoreCase);
Match match = regex.Match(busca);
if (match.Success)
{
    Console.WriteLine("string encontrada no texto.");
}
else
{
    Console.WriteLine("string não encontrada.");
}

Por meio desses exemplos, conseguimos enxergar o poder que temos na utilização de expressões regulares! E no .NET, usando a classe Regex, fica ainda mais fácil!

Conclusão

Neste artigo nosso objetivo foi apresentar o que são as regex, desde a definição até a aplicabilidade em programação. Entendemos que aplicar as regex para criar expressões que validam a formatação de caracteres, ou que possibilitam a pesquisa de conteúdo específico, pode ser uma valiosa ferramenta para as pessoas desenvolvedoras, independentemente da linguagem.

Diferentes linguagens têm bibliotecas próprias para trabalhar esse recurso e no .NET não é diferente! Por isso conhecemos a classe Regex, que encapsula funcionalidades permitindo trabalhar as regex no código C#.

Também observamos que apesar da facilidade oferecida pela plataforma no momento de usar regex, escrevê-las pode ser algo desafiador, já que precisamos resumir várias informações em uma única expressão.

Para saber mais sobre expressões regulares, veja também:

André Bessa
André Bessa

Eu sou programador e instrutor de programação usando C# e .NET. Tenho graduação em Sistemas de Informação e especializações em Engenharia de Software e em Docência Superior. Tenho experiência com desenvolvimento usando Java, PHP, PostgreSQL e MySQL, além de já ter atuado com suporte e implantação de sistemas. Busco sempre aprender mais, também gosto de contribuir com o ensino e divulgação de tecnologia. Nas horas de descanço estou maratonando alguma série ou lendo meus gibis de heróis.

Veja outros artigos sobre Programação