Compartilhar via


Extraindo sequências de texto de uma string a partir de regular expressions

O objetivo deste artigo é detalhar como expressões regulares podem facilitar a extração de partes específicas de uma string, considerando para isto o uso de tipos disponibilizados nativamente pelo próprio .NET Framework.

Introdução

A extração de sequências de texto a partir de uma cadeia de caracteres representa um tipo de atividade bastante comum dentro do desenvolvimento de software. No caso específico da linguagem C#, tarefas como esta são costumeiramente implementadas empregando operações da classe String, tais como Substring, IndexOf, StartsWith e Replace.

Embora os métodos citados geralmente atendam às expectativas, existem momentos nos quais a utilização dos mesmos pode implicar em um trabalho adicional de codificação. Uma situação que ilustra bem tal fato corresponde a cenários nos quais se faz necessária a separação de partes de uma string, levando em conta para isto algum padrão de formatação como uma máscara de e-mail ou números. Uma alternativa que pode evitar grandes esforços consistiria no uso de expressões regulares, a fim de identificar trechos de texto que correspondam ao formato desejado.

Expressões regulares (também conhecidas como “regular expressions”) nada mais são do que sequências de caracteres usadas na validação ou ainda, na manipulação de cadeias de strings. Popularizado ainda nos primórdios do ambiente UNIX, este mecanismo é atualmente utilizado em larga escala por plataformas como .NET, Java e PHP em operações envolvendo o tratamento de texto.

Na próxima seção será demonstrado como expressões regulares podem ser úteis na extração de sequências de texto a partir de uma string. Basicamente, isto será possível graças à construção de um exemplo que faz uso das classes Regex, Match e MatchCollection, as quais integram o namespace System.Text.RegularExpressions.

Implementando a funcionalidade para tratamento de texto

Para implementar os projetos demonstrados nesta seção e na próxima seção foram utilizados os seguintes recursos:

  • O Microsoft Visual Studio Professional 2013 Update 4 como IDE de desenvolvimento;
  • O .NET Framework 4.5.1.

A solução descrita neste artigo foi disponibilizada no Technet Gallery, podendo ser baixada através do link:

https://gallery.technet.microsoft.com/Extraindo-sequncias-de-3ac3cb6c

A Solution a ser gerada terá por nome “ExtractingTextUsingRegex”, conforme é possível visualizar na próxima imagem:

O próximo passo será a criação de uma Class Library chamada “RegexUtils.Extensions”, como indicado a seguir:

No projeto RegexUtils.Extensions estará a implementação da classe StringRegexExtension, cujo código pode ser observado na próxima listagem. Quanto à definição deste tipo estático, é possível destacar:

  • A presença de um Extension Method chamado ExtractStringsUsingRegex. Do ponto de vista prático, um Extension Method nada mais é do que um método estático, embora um desenvolvedor possa enxergá-lo como uma operação acessível a partir da instância de uma classe já definida anteriormente (a qual é indicada obrigatoriamente por um parâmetro cujo tipo correspondente vem precedido pela palavra-chave “this”). Este tipo de construção evita a necessidade de se codificar um novo tipo, servindo como um meio para “adicionar” novos recursos a uma estrutura pré-existente. No exemplo aqui discutido, está sendo criada uma extensão que associa uma nova funcionalidade à classe String (por meio do parâmetro “value”);
  • Um segundo parâmetro chamado regularExpression conterá uma expressão regular, com esta última servindo de base para a identificação e extração de partes específicas de uma string;
  • Uma chamada ao método Matches da classe Regex é então realizada, com uma string para pesquisa e uma expressão regular sendo informadas como parâmetros. A finalidade desta ação é produzir uma instância do tipo MatchCollection, de forma que tal objeto contenha os diferentes trechos de texto que estão em conformidade com a regular expression informada;
  • Por fim, uma consulta LINQ é executada sobre o objeto do tipo MatchCollection, a fim de obter todos os valores de texto (propriedade Value) vinculados a instâncias do tipo Match. O resultado em questão é convertido através do método ToArray, de modo que a operação retorne um array de strings com todas as sequências que atendam à expressão regular utilizada.
using System.Linq;
using System.Text.RegularExpressions;
 
namespace RegexUtils.Extensions
{
    /// <summary>
    /// Extensão que permite a extração de sequências de texto
    /// de uma string, a partir do uso de regular expressions
    /// </summary>
    public static  class StringRegexExtension
    {
        /// <summary>
        /// Retorna todas as sequências de texto encontradas em
        /// uma string e que atendam a uma expressão regular fornecida
        /// como parâmetro.
        /// </summary>
        /// <param name="value">Valor a ser analisado.</param>
        /// <param name="regularExpression">Expressão regular.</param>
        /// <returns>Array com as sequências de texto encontradas.</returns>
        public static  string[] ExtractStringsUsingRegex(
            this string  value,
            string regularExpression)
        {
            MatchCollection mc =
                Regex.Matches(value, regularExpression);
 
            return (from Match m in mc
                    select m.Value).ToArray();
        }
    }
}

Testes

Prosseguindo com a demonstração do uso de expressões regulares na extração de partes de um texto, será necessário agora criar uma Console Application chamada “StringRegexExtension.Tests”:

Conforme é possível observar na próxima imagem, este novo projeto irá referenciar a Class Library implementada na seção anterior:

Já o código que define a classe Program está na próxima listagem:

  • No método Main acontecem duas invocações ao método ExtractStringsUsingRegex, com ambas fazendo uso da variável “text”. Na primeira chamada foi utilizada uma string contendo algarismos numéricos e letras, com uma expressão regular que possibilitará a extração apenas dos valores numéricos. No segundo caso, uma nova regular expression permitirá que se separem todos os e-mails válidos do restante do texto;
  • Importante destacar que nas expressões regulares não foram utilizados os símbolos “^” e “$”, os quais marcam o início e o fim de uma representação deste tipo. O objetivo disto foi possibilitar a busca das diferentes ocorrências de um padrão ao longo de cada uma das strings consideradas.
  • O resultado das chamadas ao método ExtractStringsUsingRegex serão dois arrays de strings, com os mesmos contendo os valores que coincidem com cada uma das expressões regulares empregadas. A partir disto a operação ShowResults será acionada, de maneira que sejam exibidos os retornos produzidos por ExtractStringsUsingRegex.
using System;
using System.Text;
using RegexUtils.Extensions;
 
namespace StringRegexExtension.Tests
{
    class Program
    {
        private static  void ShowResults(
            string text, string[] results)
        {
            Console.WriteLine("Conteúdo da variável text = {0}", text);
 
            StringBuilder strb = new  StringBuilder();
            strb.Append("[ ");
            foreach (string result in results)
            {
                if (strb.Length > 2)
                    strb.Append(" , ");
                strb.Append(result);
            }
            strb.Append(" ]");
 
            Console.WriteLine(
                "Strings encontradas = {0}",
                strb.ToString());
        }
 
        static void  Main(string[] args)
        {
            string text;
            string[] results;
 
            text = "x=3.452 y=4521 z= 3412";
            results = text.ExtractStringsUsingRegex(@"\d+(?:\.\d+)?");
            ShowResults(text, results);
 
            Console.WriteLine(String.Empty);
 
            text = "Para entrar em contato envie um e-mail para test@acme.com. Caso não " +
                "obtenha uma rápida resposta, encaminhe um e-mail para answers@acme.com.br.";
            results = text.ExtractStringsUsingRegex("[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*" +
                "@[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})");
            ShowResults(text, results);
 
            Console.ReadKey();
        }
    }
}

Uma última observação deve ser feita quanto ao uso de Extension Methods no Visual Studio: o IntelliSense entenderá que o método em questão é parte integrante da classe para a qual o mesmo foi implementado, como indicado na próxima imagem (desde que o namespace em que consta o Extension Method esteja declarado na seção em que se encontram os “usings” do arquivo de código-fonte).

Concluída a implementação desta aplicação de testes, será necessário executar o projeto StringRegexExtension.Tests. Ao se fazer isto, aparecerá então a seguinte tela:

Conclusão

Como demonstrado por meio do exemplo prático deste artigo, o uso de expressões regulares e de recursos existentes no namespace System.Text.RegularExpressions simplifica de maneira significativa o processo de extração de texto em strings. Além disso, a implementação de um Extension Method permitiu estender as capacidades da classe string, com a criação de um método que pode ser reutilizado nos mais variados tipos de projetos .NET.

Referências

Extension Methods (C# Programming Guide)
https://msdn.microsoft.com/en-us/library/bb383977.aspx

Match Class
https://msdn.microsoft.com/en-us/library/system.text.regularexpressions.match(v=vs.110).aspx

MatchCollection Class
https://msdn.microsoft.com/en-us/library/system.text.regularexpressions.matchcollection(v=vs.110).aspx

Regex Class
https://msdn.microsoft.com/en-us/library/system.text.regularexpressions.regex(v=vs.100).aspx

Regular Expression Language - Quick Reference
https://msdn.microsoft.com/en-us/library/az24scfc(v=vs.110).aspx