System.Text.RegularExpressions.Regex classe

Este artigo fornece observações complementares à documentação de referência para essa API.

A Regex classe representa . Mecanismo de expressão regular da NET. Você pode usar essa classe para:

  • Analise rapidamente grandes quantidades de texto para encontrar padrões de caracteres específicos.
  • Extrair, editar, substituir ou excluir substrings de texto.
  • Adicione as cadeias de caracteres extraídas a uma coleção para gerar um relatório.

Observação

Se você quiser validar uma cadeia de caracteres determinando se ela está em conformidade com um determinado padrão de expressão regular, você pode usar a System.Configuration.RegexStringValidator classe.

Para usar expressões regulares, defina o padrão que deseja identificar em um fluxo de texto usando a sintaxe documentada em Linguagem de expressão regular - referência rápida. Em seguida, você pode instanciar opcionalmente um Regex objeto. Finalmente, você chama um método que executa alguma operação, como substituir texto que corresponde ao padrão de expressão regular ou identificar uma correspondência de padrão.

Para obter mais informações sobre a linguagem de expressão regular, consulte Linguagem de expressão regular - referência rápida ou baixe e imprima um destes folhetos:

Referência rápida no formatoWord (.docx) Referência rápida em formato PDF (.pdf)

Métodos Regex vs. String

A System.String classe inclui vários métodos de pesquisa e comparação que você pode usar para executar a correspondência de padrões com texto. Por exemplo, os String.Containsmétodos , String.EndsWithe String.StartsWith e determinam se uma ocorrência de cadeia de caracteres contém uma subcadeia de caracteres especificada, e os String.IndexOfmétodos , String.IndexOfAnyString.LastIndexOf, e String.LastIndexOfAny retornam a posição inicial de uma subcadeia de caracteres especificada em uma cadeia de caracteres. Use os System.String métodos da classe quando você estiver procurando por uma cadeia de caracteres específica. Use a Regex classe quando estiver procurando um padrão específico em uma cadeia de caracteres. Para obter mais informações e exemplos, consulte Expressões regulares do .NET.

Métodos estáticos versus métodos de instância

Depois de definir um padrão de expressão regular, você pode fornecê-lo ao mecanismo de expressão regular de duas maneiras:

  • Instanciando um Regex objeto que representa a expressão regular. Para fazer isso, você passa o padrão de expressão regular para um Regex construtor. Um Regex objeto é imutável: quando você instancia um Regex objeto com uma expressão regular, a expressão regular desse objeto não pode ser alterada.

  • Fornecendo a expressão regular e o texto para pesquisar em um static (Shared no Visual Basic) Regex método. Isso permite que você use uma expressão regular sem criar explicitamente um Regex objeto.

Todos os Regex métodos de identificação de padrões incluem sobrecargas estáticas e de instância.

O mecanismo de expressão regular deve compilar um padrão específico antes que o padrão possa ser usado. Como Regex os objetos são imutáveis, esse é um procedimento único que ocorre quando um construtor de Regex classe ou um método estático é chamado. Para eliminar a necessidade de compilar repetidamente uma única expressão regular, o mecanismo de expressão regular armazena em cache as expressões regulares compiladas usadas em chamadas de método estático. Como resultado, os métodos de correspondência de padrões de expressão regular oferecem desempenho comparável para métodos estáticos e de instância. No entanto, o cache pode afetar negativamente o desempenho nos dois casos a seguir:

  • Quando você usa chamadas de método estático com um grande número de expressões regulares. Por padrão, o mecanismo de expressão regular armazena em cache as 15 expressões regulares estáticas usadas mais recentemente. Se seu aplicativo usa mais de 15 expressões regulares estáticas, algumas expressões regulares devem ser recompiladas. Para evitar essa recompilação, você pode aumentar a Regex.CacheSize propriedade.

  • Quando você instancia novos Regex objetos com expressões regulares que foram compiladas anteriormente. Por exemplo, o código a seguir define uma expressão regular para localizar palavras duplicadas em um fluxo de texto. Embora o exemplo use uma única expressão regular, ele instancia um novo Regex objeto para processar cada linha de texto. Isso resulta na recompilação da expressão regular com cada iteração do loop.

    StreamReader sr = new StreamReader(filename);
    string input;
    string pattern = @"\b(\w+)\s\1\b";
    while (sr.Peek() >= 0)
    {
       input = sr.ReadLine();
       Regex rgx = new Regex(pattern, RegexOptions.IgnoreCase);
       MatchCollection matches = rgx.Matches(input);
       if (matches.Count > 0)
       {
          Console.WriteLine("{0} ({1} matches):", input, matches.Count);
          foreach (Match match in matches)
             Console.WriteLine("   " + match.Value);
       }
    }
    sr.Close();
    
    Dim sr As New StreamReader(filename)
    Dim input As String
    Dim pattern As String = "\b(\w+)\s\1\b"
    Do While sr.Peek() >= 0
       input = sr.ReadLine()
       Dim rgx As New Regex(pattern, RegexOptions.IgnoreCase)
       Dim matches As MatchCollection = rgx.Matches(input)
       If matches.Count > 0 Then
          Console.WriteLine("{0} ({1} matches):", input, matches.Count)
          For Each match As Match In matches
             Console.WriteLine("   " + match.Value)
          Next   
       End If
    Loop
    sr.Close()
    

    Para impedir a recompilação, você deve instanciar um único Regex objeto que seja acessível a todo o código que o exija, conforme mostrado no exemplo reescrito a seguir.

    StreamReader sr = new StreamReader(filename);
    string input;
    string pattern = @"\b(\w+)\s\1\b";
    Regex rgx = new Regex(pattern, RegexOptions.IgnoreCase);
    
    while (sr.Peek() >= 0)
    {
       input = sr.ReadLine();
       MatchCollection matches = rgx.Matches(input);
       if (matches.Count > 0)
       {
          Console.WriteLine("{0} ({1} matches):", input, matches.Count);
          foreach (Match match in matches)
             Console.WriteLine("   " + match.Value);
       }
    }
    sr.Close();
    
    Dim sr As New StreamReader(filename)
    Dim input As String
    Dim pattern As String = "\b(\w+)\s\1\b"
    Dim rgx As New Regex(pattern, RegexOptions.IgnoreCase)
    Do While sr.Peek() >= 0
       input = sr.ReadLine()
       Dim matches As MatchCollection = rgx.Matches(input)
       If matches.Count > 0 Then
          Console.WriteLine("{0} ({1} matches):", input, matches.Count)
          For Each match As Match In matches
             Console.WriteLine("   " + match.Value)
          Next   
       End If
    Loop
    sr.Close()
    

Executar operações de expressão regular

Se você decidir instanciar um Regex objeto e chamar seus métodos ou chamar métodos estáticos, a Regex classe oferece a seguinte funcionalidade de correspondência de padrão:

  • Validação de uma correspondência. Você chama o IsMatch método para determinar se uma correspondência está presente.

  • Recuperação de uma única partida. Você chama o Match método para recuperar um Match objeto que representa a primeira correspondência em uma cadeia de caracteres ou em parte de uma cadeia de caracteres. As correspondências subsequentes podem ser recuperadas chamando o Match.NextMatch método.

  • Recuperação de todas as partidas. Você chama o Matches método para recuperar um System.Text.RegularExpressions.MatchCollection objeto que representa todas as correspondências encontradas em uma cadeia de caracteres ou em parte de uma cadeia de caracteres.

  • Substituição de texto correspondente. Você chama o método para substituir o Replace texto correspondente. O texto de substituição também pode ser definido por uma expressão regular. Além disso, alguns dos Replace métodos incluem um MatchEvaluator parâmetro que permite definir programaticamente o texto de substituição.

  • Criação de uma matriz de cadeia de caracteres que é formada a partir de partes de uma cadeia de caracteres de entrada. Você chama o Split método para dividir uma cadeia de caracteres de entrada em posições definidas pela expressão regular.

Além de seus métodos de correspondência de padrões, a Regex classe inclui vários métodos de propósito especial:

  • O Escape método escapa de quaisquer caracteres que podem ser interpretados como operadores de expressão regular em uma expressão regular ou cadeia de caracteres de entrada.
  • O Unescape método remove esses caracteres de escape.
  • O CompileToAssembly método cria um assembly que contém expressões regulares predefinidas. O .NET contém exemplos desses assemblies de finalidade especial no System.Web.RegularExpressions namespace.

Definir um valor de tempo limite

O .NET oferece suporte a uma linguagem de expressão regular completa que fornece poder e flexibilidade substanciais na correspondência de padrões. No entanto, o poder e a flexibilidade têm um custo: o risco de mau desempenho. Expressões regulares com desempenho ruim são surpreendentemente fáceis de criar. Em alguns casos, as operações de expressão regular que dependem de retrocesso excessivo podem parecer parar de responder quando processam texto que quase corresponde ao padrão de expressão regular. Para obter mais informações sobre o mecanismo de expressão regular do .NET, consulte Detalhes do comportamento da expressão regular. Para obter mais informações sobre retrocesso excessivo, consulte Backtracking.

A partir do .NET Framework 4.5, você pode definir um intervalo de tempo limite para correspondências de expressões regulares para limitar o retrocesso excessivo. Dependendo do padrão de expressão regular e do texto de entrada, o tempo de execução pode exceder o intervalo de tempo limite especificado, mas não gastará mais tempo de retrocesso do que o intervalo de tempo limite especificado. Se o mecanismo de expressão regular atingir o tempo limite, ele lançará uma RegexMatchTimeoutException exceção. Na maioria dos casos, isso impede que o mecanismo de expressão regular desperdice poder de processamento ao tentar corresponder ao texto que quase corresponde ao padrão de expressão regular. Isso também pode indicar, no entanto, que o intervalo de tempo limite foi definido muito baixo ou que a carga atual da máquina causou uma degradação geral no desempenho.

A forma como você lida com a exceção depende da causa da exceção. Se a exceção ocorrer porque o intervalo de tempo limite está definido muito baixo ou devido à carga excessiva da máquina, você pode aumentar o intervalo de tempo limite e tentar novamente a operação correspondente. Se a exceção ocorrer porque a expressão regular depende de retrocesso excessivo, você pode assumir que uma correspondência não existe e, opcionalmente, você pode registrar informações que o ajudarão a modificar o padrão de expressão regular.

Você pode definir um intervalo de tempo limite chamando o Regex(String, RegexOptions, TimeSpan) construtor ao instanciar um objeto de expressão regular. Para métodos estáticos, você pode definir um intervalo de tempo limite chamando uma sobrecarga de um método correspondente que tenha um matchTimeout parâmetro. Se você não definir um valor de tempo limite explicitamente, o valor de tempo limite padrão será determinado da seguinte maneira:

  • Usando o valor de tempo limite de todo o aplicativo, se existir um. Defina o valor de tempo limite em todo o aplicativo chamando o AppDomain.SetData método para atribuir a representação de cadeia de caracteres de um TimeSpan valor à REGEX_DEFAULT_MATCH_TIMEOUT propriedade.
  • Usando o valor InfiniteMatchTimeout, se nenhum valor de tempo limite de todo o aplicativo tiver sido definido.

Importante

Recomendamos que você defina um valor de tempo limite em todas as operações de correspondência de padrão de expressão regular. Para obter mais informações, consulte Práticas recomendadas para expressões regulares.

Exemplos

O exemplo a seguir usa uma expressão regular para verificar ocorrências repetidas de palavras em uma cadeia de caracteres. A expressão \b(?<word>\w+)\s+(\k<word>)\b regular pode ser interpretada como mostrado na tabela a seguir.

Padrão Descrição
\b Inicie a partida em um limite de palavras.
(?<word>\w+) Corresponder um ou mais caracteres de palavra até um limite de palavra. Nomeie este grupo wordcapturado .
\s+ Corresponde a um ou mais caracteres de espaço em branco.
(\k<word>) Corresponda ao grupo capturado chamado word.
\b Corresponder a um limite de palavra.
using System;
using System.Text.RegularExpressions;

public class Test
{
    public static void Main ()
    {
        // Define a regular expression for repeated words.
        Regex rx = new Regex(@"\b(?<word>\w+)\s+(\k<word>)\b",
          RegexOptions.Compiled | RegexOptions.IgnoreCase);

        // Define a test string.
        string text = "The the quick brown fox  fox jumps over the lazy dog dog.";

        // Find matches.
        MatchCollection matches = rx.Matches(text);

        // Report the number of matches found.
        Console.WriteLine("{0} matches found in:\n   {1}",
                          matches.Count,
                          text);

        // Report on each match.
        foreach (Match match in matches)
        {
            GroupCollection groups = match.Groups;
            Console.WriteLine("'{0}' repeated at positions {1} and {2}",
                              groups["word"].Value,
                              groups[0].Index,
                              groups[1].Index);
        }
    }
}

// The example produces the following output to the console:
//       3 matches found in:
//          The the quick brown fox  fox jumps over the lazy dog dog.
//       'The' repeated at positions 0 and 4
//       'fox' repeated at positions 20 and 25
//       'dog' repeated at positions 49 and 53
Imports System.Text.RegularExpressions

Public Module Test

    Public Sub Main()
        ' Define a regular expression for repeated words.
        Dim rx As New Regex("\b(?<word>\w+)\s+(\k<word>)\b", _
               RegexOptions.Compiled Or RegexOptions.IgnoreCase)

        ' Define a test string.        
        Dim text As String = "The the quick brown fox  fox jumps over the lazy dog dog."
        
        ' Find matches.
        Dim matches As MatchCollection = rx.Matches(text)

        ' Report the number of matches found.
        Console.WriteLine("{0} matches found in:", matches.Count)
        Console.WriteLine("   {0}", text)

        ' Report on each match.
        For Each match As Match In matches
            Dim groups As GroupCollection = match.Groups
            Console.WriteLine("'{0}' repeated at positions {1} and {2}", _ 
                              groups.Item("word").Value, _
                              groups.Item(0).Index, _
                              groups.Item(1).Index)
        Next
    End Sub
End Module
' The example produces the following output to the console:
'       3 matches found in:
'          The the quick brown fox  fox jumps over the lazy dog dog.
'       'The' repeated at positions 0 and 4
'       'fox' repeated at positions 20 and 25
'       'dog' repeated at positions 49 and 53

O próximo exemplo ilustra o uso de uma expressão regular para verificar se uma cadeia de caracteres representa um valor de moeda ou tem o formato correto para representar um valor de moeda. Nesse caso, a expressão regular é construída dinamicamente a NumberFormatInfo.CurrencyDecimalSeparatorpartir das propriedades , CurrencyDecimalDigits, NumberFormatInfo.CurrencySymbolNumberFormatInfo.NegativeSign, , e NumberFormatInfo.PositiveSign para a cultura en-US. A expressão regular resultante é ^\s*[\+-]?\s?\$?\s?(\d*\.?\d{2}?){1}$. Essa expressão regular pode ser interpretada como mostrado na tabela a seguir.

Padrão Descrição
^ Comece no início da cadeia de caracteres.
\s* Corresponder a zero ou mais caracteres de espaço em branco.
[\+-]? Corresponder zero ou uma ocorrência do sinal positivo ou do sinal negativo.
\s? Corresponder a zero ou a um caractere de espaço em branco.
\$? Corresponda a zero ou uma ocorrência do cifrão.
\s? Corresponder a zero ou a um caractere de espaço em branco.
\d* Corresponde a zero ou mais dígitos decimais.
\.? Corresponder a zero ou um símbolo de ponto decimal.
(\d{2})? Grupo de captura 1: corresponda a dois dígitos decimais zero ou uma vez.
(\d*\.?(\d{2})?){1} Corresponder ao padrão de dígitos integrais e fracionários separados por um símbolo de ponto decimal pelo menos uma vez.
$ Corresponder ao final da cadeia de caracteres.

Nesse caso, a expressão regular pressupõe que uma cadeia de caracteres de moeda válida não contém símbolos separadores de grupo e que ela não tem dígitos fracionários ou o número de dígitos fracionários definidos pela propriedade da CurrencyDecimalDigits cultura especificada.

using System;
using System.Globalization;
using System.Text.RegularExpressions;

public class Example
{
    public static void Main()
    {
        // Get the en-US NumberFormatInfo object to build the regular 
        // expression pattern dynamically.
        NumberFormatInfo nfi = CultureInfo.GetCultureInfo("en-US").NumberFormat;

        // Define the regular expression pattern.
        string pattern;
        pattern = @"^\s*[";
        // Get the positive and negative sign symbols.
        pattern += Regex.Escape(nfi.PositiveSign + nfi.NegativeSign) + @"]?\s?";
        // Get the currency symbol.
        pattern += Regex.Escape(nfi.CurrencySymbol) + @"?\s?";
        // Add integral digits to the pattern.
        pattern += @"(\d*";
        // Add the decimal separator.
        pattern += Regex.Escape(nfi.CurrencyDecimalSeparator) + "?";
        // Add the fractional digits.
        pattern += @"(\d{";
        // Determine the number of fractional digits in currency values.
        pattern += nfi.CurrencyDecimalDigits.ToString() + "})?){1}$";

        Console.WriteLine($"Pattern is {pattern}\n");

        Regex rgx = new Regex(pattern);

        // Define some test strings.
        string[] tests = { "-42", "19.99", "0.001", "100 USD",
                         ".34", "0.34", "1,052.21", "$10.62",
                         "+1.43", "-$0.23" };

        // Check each test string against the regular expression.
        foreach (string test in tests)
        {
            if (rgx.IsMatch(test))
                Console.WriteLine($"{test} is a currency value.");
            else
                Console.WriteLine($"{test} is not a currency value.");
        }
    }
}
// The example displays the following output:
//       Pattern is ^\s*[\+-]?\s?\$?\s?(\d*\.?(\d{2})?){1}$
//
//       -42 is a currency value.
//       19.99 is a currency value.
//       0.001 is not a currency value.
//       100 USD is not a currency value.
//       .34 is a currency value.
//       0.34 is a currency value.
//       1,052.21 is not a currency value.
//       $10.62 is a currency value.
//       +1.43 is a currency value.
//       -$0.23 is a currency value.
Imports System.Globalization
Imports System.Text.RegularExpressions

Public Module Example
   Public Sub Main()
      ' Get the current NumberFormatInfo object to build the regular 
      ' expression pattern dynamically.
      Dim nfi As NumberFormatInfo = CultureInfo.GetCultureInfo("en-US").NumberFormat

      ' Define the regular expression pattern.
      Dim pattern As String 
      pattern = "^\s*["
      ' Get the positive and negative sign symbols.
      pattern += Regex.Escape(nfi.PositiveSign + nfi.NegativeSign) + "]?\s?"
      ' Get the currency symbol.
      pattern += Regex.Escape(nfi.CurrencySymbol) + "?\s?"
      ' Add integral digits to the pattern.
      pattern += "(\d*"
      ' Add the decimal separator.
      pattern += Regex.Escape(nfi.CurrencyDecimalSeparator) + "?"
      ' Add the fractional digits.
      pattern += "(\d{"
      ' Determine the number of fractional digits in currency values.
      pattern += nfi.CurrencyDecimalDigits.ToString() + "})?){1}$"
      
      Console.WriteLine("Pattern is {0}", pattern)
      Console.WriteLine()
      
      Dim rgx As New Regex(pattern)

      ' Define some test strings.
      Dim tests() As String = {"-42", "19.99", "0.001", "100 USD", _
                               ".34", "0.34", "1,052.21", "$10.62", _
                               "+1.43", "-$0.23" }

      ' Check each test string against the regular expression.
      For Each test As String In tests
         If rgx.IsMatch(test) Then
            Console.WriteLine("{0} is a currency value.", test)
         Else
            Console.WriteLine("{0} is not a currency value.", test)
         End If
      Next
   End Sub
End Module
' The example displays the following output:
'       Pattern is ^\s*[\+-]?\s?\$?\s?(\d*\.?(\d{2})?){1}$
'
'       -42 is a currency value.
'       19.99 is a currency value.
'       0.001 is not a currency value.
'       100 USD is not a currency value.
'       .34 is a currency value.
'       0.34 is a currency value.
'       1,052.21 is not a currency value.
'       $10.62 is a currency value.
'       +1.43 is a currency value.
'       -$0.23 is a currency value.

Como a expressão regular neste exemplo é criada dinamicamente, você não sabe, em tempo de design, se o símbolo de moeda, o sinal decimal ou os sinais positivos e negativos da cultura especificada (en-US neste exemplo) podem ser mal interpretados pelo mecanismo de expressão regular como operadores de linguagem de expressão regular. Para evitar qualquer interpretação incorreta, o exemplo passa cada cadeia de caracteres gerada dinamicamente para o Escape método.