Retrocesso em expressões regularesBacktracking in Regular Expressions

O retrocesso ocorre quando um padrão de expressão regular contém quantificadores opcionais ou constructos de alternância e o mecanismo de expressões regulares retorna a um estado salvo anterior para retomar sua pesquisa por uma correspondência.Backtracking occurs when a regular expression pattern contains optional quantifiers or alternation constructs, and the regular expression engine returns to a previous saved state to continue its search for a match. O retrocesso é indispensável para o poder das expressões regulares, ele permite que as expressões sejam poderosas e flexíveis e correspondam a padrões muito complexos.Backtracking is central to the power of regular expressions; it makes it possible for expressions to be powerful and flexible, and to match very complex patterns. No entanto, todo esse poder tem um custo.At the same time, this power comes at a cost. O retrocesso muitas vezes é o fator individual que mais afeta o desempenho do mecanismo de expressões regulares.Backtracking is often the single most important factor that affects the performance of the regular expression engine. Felizmente, o desenvolvedor tem controle sobre o comportamento do mecanismo de expressões regulares e como ele usa o retrocesso.Fortunately, the developer has control over the behavior of the regular expression engine and how it uses backtracking. Este tópico explica como o retrocesso funciona e como ele pode ser controlado.This topic explains how backtracking works and how it can be controlled.

Observação

Em geral, um mecanismo de NFA (Automação Finita Não Determinística), como o mecanismo de expressões regulares .NET, coloca a responsabilidade pela criação de expressões regulares eficientes e rápidas nas mãos do desenvolvedor.In general, a Nondeterministic Finite Automaton (NFA) engine like .NET regular expression engine places the responsibility for crafting efficient, fast regular expressions on the developer.

Comparação linear sem retrocessoLinear Comparison Without Backtracking

Se um padrão de expressão regular não tem quantificadores ou constructos de alternância opcionais, o mecanismo de expressões regulares é executado em tempo linear.If a regular expression pattern has no optional quantifiers or alternation constructs, the regular expression engine executes in linear time. Ou seja, depois que o mecanismo de expressões regulares corresponde o primeiro elemento de linguagem no padrão com o texto da cadeia de caracteres de entrada, ele tenta corresponder o elemento de linguagem seguinte no padrão com o próximo caractere ou grupo de caracteres na cadeia de caracteres de entrada.That is, after the regular expression engine matches the first language element in the pattern with text in the input string, it tries to match the next language element in the pattern with the next character or group of characters in the input string. Esse processo continuará até que a correspondência obtenha êxito ou falhe.This continues until the match either succeeds or fails. Em ambos os casos, o mecanismo de expressões regulares avança um caractere de cada vez na cadeia de caracteres de entrada.In either case, the regular expression engine advances by one character at a time in the input string.

O exemplo a seguir ilustra esse cenário.The following example provides an illustration. A expressão regular e{2}\w\b procura duas ocorrências da letra “e” seguidas por qualquer caractere de palavra seguido por um limite de palavra.The regular expression e{2}\w\b looks for two occurrences of the letter "e" followed by any word character followed by a word boundary.

using System;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      string input = "needing a reed";
      string pattern = @"e{2}\w\b";
      foreach (Match match in Regex.Matches(input, pattern))
         Console.WriteLine("{0} found at position {1}",
                           match.Value, match.Index);
   }
}
// The example displays the following output:
//       eed found at position 11
Imports System.Text.RegularExpressions

Module Example
    Public Sub Main()
        Dim input As String = "needing a reed"
        Dim pattern As String = "e{2}\w\b"
        For Each match As Match In Regex.Matches(input, pattern)
            Console.WriteLine("{0} found at position {1}", _
                              match.Value, match.Index)
        Next
    End Sub
End Module
' The example displays the following output:
'       eed found at position 11

Embora essa expressão regular inclua o quantificador {2}, ela é avaliada de uma maneira linear.Although this regular expression includes the quantifier {2}, it is evaluated in a linear manner. O mecanismo de expressões regulares não retrocede porque {2} não é um quantificador opcional, ele especifica um número exato e não um número variável de vezes que a subexpressão anterior deve corresponder.The regular expression engine does not backtrack because {2} is not an optional quantifier; it specifies an exact number and not a variable number of times that the previous subexpression must match. Como resultado, o mecanismo de expressões regulares tenta corresponder o padrão da expressão regular com a cadeia de caracteres de entrada conforme mostrado na tabela a seguir.As a result, the regular expression engine tries to match the regular expression pattern with the input string as shown in the following table.

OperaçãoOperation Posição no padrãoPosition in pattern Posição na cadeia de caracteresPosition in string ResultadoResult
11 ee "needing a reed" (índice 0)"needing a reed" (index 0) Nenhuma correspondência.No match.
22 ee "eeding a reed" (índice 1)"eeding a reed" (index 1) Possível correspondência.Possible match.
33 e{2}e{2} "eding a reed" (índice 2)"eding a reed" (index 2) Possível correspondência.Possible match.
44 \w\w "ding a reed" (índice 3)"ding a reed" (index 3) Possível correspondência.Possible match.
55 \b\b "ing a reed" (índice 4)"ing a reed" (index 4) Possível falha de correspondência.Possible match fails.
66 ee "eding a reed" (índice 2)"eding a reed" (index 2) Possível correspondência.Possible match.
77 e{2}e{2} "ding a reed" (índice 3)"ding a reed" (index 3) Possível falha de correspondência.Possible match fails.
88 ee "ding a reed" (índice 3)"ding a reed" (index 3) Falha de correspondência.Match fails.
99 ee "ing a reed" (índice 4)"ing a reed" (index 4) Nenhuma correspondência.No match.
1010 ee "ng a reed" (índice 5)"ng a reed" (index 5) Nenhuma correspondência.No match.
1111 ee "g a reed" (índice 6)"g a reed" (index 6) Nenhuma correspondência.No match.
1212 ee " a reed" (índice 7)" a reed" (index 7) Nenhuma correspondência.No match.
1313 ee "a reed" (índice 8)"a reed" (index 8) Nenhuma correspondência.No match.
1414 ee " reed" (índice 9)" reed" (index 9) Nenhuma correspondência.No match.
1515 ee "reed" (índice 10)"reed" (index 10) Nenhuma correspondênciaNo match
1616 ee "eed" (índice 11)"eed" (index 11) Possível correspondência.Possible match.
1717 e{2}e{2} "ed" (índice 12)"ed" (index 12) Possível correspondência.Possible match.
1818 \w\w "d" (índice 13)"d" (index 13) Possível correspondência.Possible match.
1919 \b\b "" (índice 14)"" (index 14) Correspondência.Match.

Se um padrão de expressão regular não inclui nenhum quantificador ou construtor de alternância opcional, o número máximo de comparações necessárias para corresponder ao padrão da expressão regular com a cadeia de caracteres de entrada é aproximadamente equivalente ao número de caracteres na cadeia de caracteres de entrada.If a regular expression pattern includes no optional quantifiers or alternation constructs, the maximum number of comparisons required to match the regular expression pattern with the input string is roughly equivalent to the number of characters in the input string. Nesse caso, o mecanismo de expressões regulares usa 19 comparações para identificar possíveis correspondências nesta cadeia de 13 caracteres.In this case, the regular expression engine uses 19 comparisons to identify possible matches in this 13-character string. Em outras palavras, o mecanismo de expressões regulares é executado em tempo quase linear se não contém quantificadores ou construtores de alternância opcionais.In other words, the regular expression engine runs in near-linear time if it contains no optional quantifiers or alternation constructs.

Retrocesso com quantificadores opcionais ou construtores de alternânciaBacktracking with Optional Quantifiers or Alternation Constructs

Quando uma expressão regular inclui quantificadores ou construtores de alternância opcionais, a avaliação da cadeia de caracteres de entrada deixa de ser linear.When a regular expression includes optional quantifiers or alternation constructs, the evaluation of the input string is no longer linear. A correspondência de padrões com um mecanismo NFA é orientada pelos elementos de linguagem da expressão regular e não pelos caracteres a serem correspondidos na cadeia de caracteres de entrada.Pattern matching with an NFA engine is driven by the language elements in the regular expression and not by the characters to be matched in the input string. Assim, o mecanismo de expressões regulares tenta fazer a correspondência total de subexpressões opcionais ou alternativas.Therefore, the regular expression engine tries to fully match optional or alternative subexpressions. Quando ele avança para o elemento de linguagem seguinte na subexpressão e a correspondência falha, o mecanismo de expressões regulares pode abandonar uma parte de sua correspondência bem-sucedida e retornar a um estado salvo anteriormente com o objetivo de corresponder a expressão regular inteira com a cadeia de caracteres de entrada.When it advances to the next language element in the subexpression and the match is unsuccessful, the regular expression engine can abandon a portion of its successful match and return to an earlier saved state in the interest of matching the regular expression as a whole with the input string. Esse processo de retornar a um estado salvo anterior para localizar uma correspondência é conhecido como o retrocesso.This process of returning to a previous saved state to find a match is known as backtracking.

Por exemplo, considere o padrão de expressão regular .*(es), o qual corresponde os caracteres “es” e todos os caracteres que os precedem.For example, consider the regular expression pattern .*(es), which matches the characters "es" and all the characters that precede it. Como mostra o exemplo a seguir, se a cadeia de caracteres de entrada é "Essential services are provided by regular expressions." (Serviços essenciais são fornecidos por expressões regulares.), o padrão corresponde a cadeia de caracteres até o “es” (inclusive) em "expressions”.As the following example shows, if the input string is "Essential services are provided by regular expressions.", the pattern matches the whole string up to and including the "es" in "expressions".

using System;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      string input = "Essential services are provided by regular expressions.";
      string pattern = ".*(es)";
      Match m = Regex.Match(input, pattern, RegexOptions.IgnoreCase);
      if (m.Success) {
         Console.WriteLine("'{0}' found at position {1}",
                           m.Value, m.Index);
         Console.WriteLine("'es' found at position {0}",
                           m.Groups[1].Index);
      }
   }
}
//    'Essential services are provided by regular expres' found at position 0
//    'es' found at position 47
Imports System.Text.RegularExpressions

Module Example
    Public Sub Main()
        Dim input As String = "Essential services are provided by regular expressions."
        Dim pattern As String = ".*(es)"
        Dim m As Match = Regex.Match(input, pattern, RegexOptions.IgnoreCase)
        If m.Success Then
            Console.WriteLine("'{0}' found at position {1}", _
                              m.Value, m.Index)
            Console.WriteLine("'es' found at position {0}", _
                              m.Groups(1).Index)
        End If
    End Sub
End Module
'    'Essential services are provided by regular expres' found at position 0
'    'es' found at position 47

Para fazer isso, o mecanismo de expressões regulares usa o retrocesso da seguinte forma:To do this, the regular expression engine uses backtracking as follows:

  • Ele corresponde o .* (que corresponde a zero, uma ou mais ocorrências de qualquer caractere) com a cadeia de caracteres de entrada inteira.It matches the .* (which matches zero, one, or more occurrences of any character) with the whole input string.

  • Ele tenta corresponder “e” no padrão da expressão regular.It attempts to match "e" in the regular expression pattern. No entanto, a cadeia de caracteres de entrada não tem nenhum caractere restante disponível para corresponder.However, the input string has no remaining characters available to match.

  • Ele retrocede para sua última correspondência bem-sucedida, "Essential services are provided by regular expressions", e tenta corresponder “e” com o ponto no final da frase.It backtracks to its last successful match, "Essential services are provided by regular expressions", and attempts to match "e" with the period at the end of the sentence. A correspondência falha.The match fails.

  • Ele continua a retroceder para uma correspondência bem-sucedida anterior um caractere de cada vez até que a subcadeia de caracteres provisória correspondente seja “Essential services are provided by regular expr".It continues to backtrack to a previous successful match one character at a time until the tentatively matched substring is "Essential services are provided by regular expr". Ele então compara o “e” no padrão com o segundo “e” em “expressions” e encontra uma correspondência.It then compares the "e" in the pattern to the second "e" in "expressions" and finds a match.

  • Ele compara o “s” no padrão com o “s” após o caractere “e” que já foi correspondido (o primeiro “s” em “expressions”).It compares "s" in the pattern to the "s" that follows the matched "e" character (the first "s" in "expressions"). A correspondência é bem-sucedida.The match is successful.

Quando o retrocesso é usado, corresponder o padrão de expressão regular com a cadeia de caracteres de entrada, que tem 55 caracteres de comprimento, requer 67 operações de comparação.When you use backtracking, matching the regular expression pattern with the input string, which is 55 characters long, requires 67 comparison operations. Geralmente, se um padrão de expressão regular tem um único constructo de alternância ou um único quantificador opcional, o número de operações de comparação necessárias para corresponder ao padrão é mais que duas vezes maior do que o número de caracteres na cadeia de caracteres de entrada.Generally, if a regular expression pattern has a single alternation construct or a single optional quantifier, the number of comparison operations required to match the pattern is more than twice the number of characters in the input string.

Retrocesso com quantificadores opcionais aninhadosBacktracking with Nested Optional Quantifiers

O número de operações de comparação necessárias para corresponder a um padrão de expressão regular pode aumentar exponencialmente se o padrão inclui um grande número de construtores de alternância, se ele inclui construtores de alternância aninhados ou, mais comumente, se ele inclui quantificadores opcionais aninhados.The number of comparison operations required to match a regular expression pattern can increase exponentially if the pattern includes a large number of alternation constructs, if it includes nested alternation constructs, or, most commonly, if it includes nested optional quantifiers. Por exemplo, o padrão de expressão regular ^(a+)+$ foi criado para corresponder a uma cadeia de caracteres completa que contém um ou mais caracteres “a”.For example, the regular expression pattern ^(a+)+$ is designed to match a complete string that contains one or more "a" characters. O exemplo fornece duas cadeias de caracteres de entrada de comprimento idêntico, mas somente a primeira cadeia de caracteres corresponde ao padrão.The example provides two input strings of identical length, but only the first string matches the pattern. A classe System.Diagnostics.Stopwatch é usada para determinar a duração da operação de correspondência.The System.Diagnostics.Stopwatch class is used to determine how long the match operation takes.

using System;
using System.Diagnostics;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      string pattern = "^(a+)+$";
      string[] inputs = { "aaaaaa", "aaaaa!" };
      Regex rgx = new Regex(pattern);
      Stopwatch sw;

      foreach (string input in inputs) {
         sw = Stopwatch.StartNew();
         Match match = rgx.Match(input);
         sw.Stop();
         if (match.Success)
            Console.WriteLine("Matched {0} in {1}", match.Value, sw.Elapsed);
         else
            Console.WriteLine("No match found in {0}", sw.Elapsed);
      }
   }
}
Imports System.Diagnostics
Imports System.Text.RegularExpressions

Module Example
    Public Sub Main()
        Dim pattern As String = "^(a+)+$"
        Dim inputs() As String = {"aaaaaa", "aaaaa!"}
        Dim rgx As New Regex(pattern)
        Dim sw As Stopwatch

        For Each input As String In inputs
            sw = Stopwatch.StartNew()
            Dim match As Match = rgx.Match(input)
            sw.Stop()
            If match.Success Then
                Console.WriteLine("Matched {0} in {1}", match.Value, sw.Elapsed)
            Else
                Console.WriteLine("No match found in {0}", sw.Elapsed)
            End If
        Next
    End Sub
End Module

Como a saída do exemplo mostra, o mecanismo de expressões regulares demora aproximadamente duas vezes mais tempo para descobrir que uma cadeia de caracteres de entrada não correspondeu ao padrão do que o tempo que foi necessário para identificar uma cadeia de caracteres compatível.As the output from the example shows, the regular expression engine took about twice as long to find that an input string did not match the pattern as it did to identify a matching string. Isso acontece porque uma correspondência malsucedida sempre representa um cenário de pior caso.This is because an unsuccessful match always represents a worst-case scenario. O mecanismo de expressões regulares deve usar a expressão regular para seguir todos os caminhos possíveis através dos dados antes de concluir que a correspondência falhou e os parênteses aninhados criam vários caminhos adicionais nos dados.The regular expression engine must use the regular expression to follow all possible paths through the data before it can conclude that the match is unsuccessful, and the nested parentheses create many additional paths through the data. O mecanismo de expressões regulares conclui que a segunda cadeia de caracteres não correspondeu ao padrão ao fazer o seguinte:The regular expression engine concludes that the second string did not match the pattern by doing the following:

  • Ele verifica que estava no início da cadeia de caracteres e então corresponde os primeiros cinco caracteres da cadeia de caracteres com o padrão a+.It checks that it was at the beginning of the string, and then matches the first five characters in the string with the pattern a+. Ele então determina que não há grupos adicionais de caracteres “a” na cadeia de caracteres.It then determines that there are no additional groups of "a" characters in the string. Finalmente, ele testa o final da cadeia de caracteres.Finally, it tests for the end of the string. Como um caractere adicional permanece na cadeia de caracteres, a correspondência falha.Because one additional character remains in the string, the match fails. Essa correspondência com falha requer 9 comparações.This failed match requires 9 comparisons. O mecanismo de expressões regulares também salva as informações de estado de suas correspondências de “a” (as quais chamaremos a correspondência 1), "aa” (correspondência 2), "aaa" (correspondência 3) e “aaaa" (correspondência 4).The regular expression engine also saves state information from its matches of "a" (which we will call match 1), "aa" (match 2), "aaa" (match 3), and "aaaa" (match 4).

  • Ele retorna à correspondência 4 salva anteriormente.It returns to the previously saved match 4. Ele determina que há um caractere adicional “a” a ser atribuído a um grupo capturado adicional.It determines that there is one additional "a" character to assign to an additional captured group. Finalmente, ele testa o final da cadeia de caracteres.Finally, it tests for the end of the string. Como um caractere adicional permanece na cadeia de caracteres, a correspondência falha.Because one additional character remains in the string, the match fails. Essa correspondência com falha requer 4 comparações.This failed match requires 4 comparisons. Até agora, foi executado um total de 13 comparações.So far, a total of 13 comparisons have been performed.

  • Ele retorna à correspondência 3 salva anteriormente.It returns to the previously saved match 3. Ele determina que há dois caracteres adicionais “a” a serem atribuídos a um grupo capturado adicional.It determines that there are two additional "a" characters to assign to an additional captured group. No entanto, o teste de fim da cadeia de caracteres falha.However, the end-of-string test fails. Ele então retorna para a correspondência 3 e tenta corresponder os dois caracteres adicionais “a” em dois grupos capturados adicionais.It then returns to match3 and tries to match the two additional "a" characters in two additional captured groups. No entanto, o teste de fim da cadeia de caracteres continua a falhar.The end-of-string test still fails. Essas correspondências com falha exigem 12 comparações.These failed matches require 12 comparisons. Até agora, foi executado um total de 25 comparações.So far, a total of 25 comparisons have been performed.

A comparação de cadeia de caracteres de entrada com a expressão regular continuará dessa forma até que o mecanismo de expressão regular tente todas as combinações possíveis de correspondências e conclua que não há nenhuma correspondência.Comparison of the input string with the regular expression continues in this way until the regular expression engine has tried all possible combinations of matches, and then concludes that there is no match. Devido aos quantificadores aninhados, essa comparação é O(2n) ou uma operação exponencial, em que n é o número de caracteres na cadeia de caracteres de entrada.Because of the nested quantifiers, this comparison is an O(2n) or an exponential operation, where n is the number of characters in the input string. Isso significa que, no pior caso, uma cadeia de caracteres de entrada com 30 caracteres requer aproximadamente 1.073.741.824 comparações e uma cadeia de caracteres de entrada com 40 caracteres requer aproximadamente 1.099.511.627.776 comparações.This means that in the worst case, an input string of 30 characters requires approximately 1,073,741,824 comparisons, and an input string of 40 characters requires approximately 1,099,511,627,776 comparisons. Se você usar cadeias de caracteres com esses tamanhos ou até mesmo com tamanhos maiores, os métodos de expressões regulares poderão demorar um tempo extremamente longo para terminar ao processarem uma entrada que não correspondam ao padrão de expressão regular.If you use strings of these or even greater lengths, regular expression methods can take an extremely long time to complete when they process input that does not match the regular expression pattern.

Controlando o retrocessoControlling Backtracking

O retrocesso permite a você criar expressões regulares avançadas e flexíveis.Backtracking lets you create powerful, flexible regular expressions. No entanto, conforme mostrado na seção anterior, esses benefícios podem estar associados a um baixo desempenho inaceitável.However, as the previous section showed, these benefits may be coupled with unacceptably poor performance. Para evitar o retrocesso excessivo, você deve definir um intervalo de tempo limite no qual você criará uma instância de um objeto Regex ou chamará um método de correspondência de expressão regular estático.To prevent excessive backtracking, you should define a time-out interval when you instantiate a Regex object or call a static regular expression matching method. Isso é abordado na próxima seção.This is discussed in the next section. Além disso, o .NET dá suporte a três elementos de linguagem de expressão regular que limitam ou suprimem o retrocesso e que dão suporte a expressões regulares complexas com pouca ou nenhuma penalidade de desempenho: grupos atômicos, asserções lookbehinde declarações de lookahead.In addition, .NET supports three regular expression language elements that limit or suppress backtracking and that support complex regular expressions with little or no performance penalty: atomic groups, lookbehind assertions, and lookahead assertions. Para saber mais sobre cada elemento de linguagem, consulte Constructos de agrupamento.For more information about each language element, see Grouping Constructs.

Definindo um intervalo de tempo limiteDefining a Time-out Interval

Do .NET Framework 4.5 em diante, você pode definir um valor de tempo limite que representa o intervalo mais longo durante o qual o mecanismo de expressão regular pesquisará uma única correspondência antes de abandonar a tentativa e gerar uma exceção RegexMatchTimeoutException.Starting with the .NET Framework 4.5, you can set a time-out value that represents the longest interval the regular expression engine will search for a single match before it abandons the attempt and throws a RegexMatchTimeoutException exception. Você especifica o intervalo de tempo limite ao fornecer um valor de TimeSpan para o construtor Regex(String, RegexOptions, TimeSpan) para instanciar expressões regulares.You specify the time-out interval by supplying a TimeSpan value to the Regex(String, RegexOptions, TimeSpan) constructor for instance regular expressions. Além disso, cada método de correspondência de padrão estático tem uma sobrecarga com um parâmetro TimeSpan que permite a você especificar um valor de tempo limite.In addition, each static pattern matching method has an overload with a TimeSpan parameter that allows you to specify a time-out value. Por padrão, o intervalo de tempo limite é definido para Regex.InfiniteMatchTimeout, o que significa que o mecanismo de expressões regulares nunca excede o tempo limite.By default, the time-out interval is set to Regex.InfiniteMatchTimeout and the regular expression engine does not time out.

Importante

É recomendável sempre definir um intervalo de tempo limite se a sua expressão regular depende de retrocesso.We recommend that you always set a time-out interval if your regular expression relies on backtracking.

Uma exceção RegexMatchTimeoutException indica que o mecanismo de expressões regulares não pôde localizar uma correspondência dentro do intervalo de tempo limite especificado, mas não indica como a exceção foi gerada.A RegexMatchTimeoutException exception indicates that the regular expression engine was unable to find a match within the specified time-out interval but does not indicate why the exception was thrown. O motivo poderia ser o retrocesso excessivo, mas também é possível que o intervalo de tempo limite tenha sido definido como um valor muito baixo considerando a carga do sistema no momento em que a exceção foi gerada.The reason might be excessive backtracking, but it is also possible that the time-out interval was set too low given the system load at the time the exception was thrown. Ao tratar a exceção, você pode escolher entre abandonar as correspondências adicionais com a cadeia de caracteres de entrada ou aumentar o intervalo de tempo limite e repetir a operação de correspondência.When you handle the exception, you can choose to abandon further matches with the input string or increase the time-out interval and retry the matching operation.

Por exemplo, o código a seguir chama o construtor Regex(String, RegexOptions, TimeSpan) para criar uma instância de um objeto Regex com um valor de tempo limite de um segundo.For example, the following code calls the Regex(String, RegexOptions, TimeSpan) constructor to instantiate a Regex object with a time-out value of one second. O padrão de expressão regular (a+)+$, que faz a correspondência de uma ou várias sequências de um ou mais caracteres de “a” no final de uma linha, está sujeito ao retrocesso excessivo.The regular expression pattern (a+)+$, which matches one or more sequences of one or more "a" characters at the end of a line, is subject to excessive backtracking. Se RegexMatchTimeoutException gerada, o exemplo aumenta o valor do tempo limite até um intervalo máximo de três segundos.If a RegexMatchTimeoutException is thrown, the example increases the time-out value up to a maximum interval of three seconds. Depois disso, ele abandona a tentativa de corresponder o padrão.After that, it abandons the attempt to match the pattern.

using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Security;
using System.Text.RegularExpressions;
using System.Threading;

public class Example
{
   const int MaxTimeoutInSeconds = 3;

   public static void Main()
   {
      string pattern = @"(a+)+$";    // DO NOT REUSE THIS PATTERN.
      Regex rgx = new Regex(pattern, RegexOptions.IgnoreCase, TimeSpan.FromSeconds(1));
      Stopwatch sw = null;

      string[] inputs= { "aa", "aaaa>",
                         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
                         "aaaaaaaaaaaaaaaaaaaaaa>",
                         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa>" };

      foreach (var inputValue in inputs) {
         Console.WriteLine("Processing {0}", inputValue);
         bool timedOut = false;
         do {
            try {
               sw = Stopwatch.StartNew();
               // Display the result.
               if (rgx.IsMatch(inputValue)) {
                  sw.Stop();
                  Console.WriteLine(@"Valid: '{0}' ({1:ss\.fffffff} seconds)",
                                    inputValue, sw.Elapsed);
               }
               else {
                  sw.Stop();
                  Console.WriteLine(@"'{0}' is not a valid string. ({1:ss\.fffff} seconds)",
                                    inputValue, sw.Elapsed);
               }
            }
            catch (RegexMatchTimeoutException e) {
               sw.Stop();
               // Display the elapsed time until the exception.
               Console.WriteLine(@"Timeout with '{0}' after {1:ss\.fffff}",
                                 inputValue, sw.Elapsed);
               Thread.Sleep(1500);       // Pause for 1.5 seconds.

               // Increase the timeout interval and retry.
               TimeSpan timeout = e.MatchTimeout.Add(TimeSpan.FromSeconds(1));
               if (timeout.TotalSeconds > MaxTimeoutInSeconds) {
                  Console.WriteLine("Maximum timeout interval of {0} seconds exceeded.",
                                    MaxTimeoutInSeconds);
                  timedOut = false;
               }
               else {
                  Console.WriteLine("Changing the timeout interval to {0}",
                                    timeout);
                  rgx = new Regex(pattern, RegexOptions.IgnoreCase, timeout);
                  timedOut = true;
               }
            }
         } while (timedOut);
         Console.WriteLine();
      }
   }
}
// The example displays output like the following :
//    Processing aa
//    Valid: 'aa' (00.0000779 seconds)
//
//    Processing aaaa>
//    'aaaa>' is not a valid string. (00.00005 seconds)
//
//    Processing aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
//    Valid: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' (00.0000043 seconds)
//
//    Processing aaaaaaaaaaaaaaaaaaaaaa>
//    Timeout with 'aaaaaaaaaaaaaaaaaaaaaa>' after 01.00469
//    Changing the timeout interval to 00:00:02
//    Timeout with 'aaaaaaaaaaaaaaaaaaaaaa>' after 02.01202
//    Changing the timeout interval to 00:00:03
//    Timeout with 'aaaaaaaaaaaaaaaaaaaaaa>' after 03.01043
//    Maximum timeout interval of 3 seconds exceeded.
//
//    Processing aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa>
//    Timeout with 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa>' after 03.01018
//    Maximum timeout interval of 3 seconds exceeded.
Imports System.ComponentModel
Imports System.Diagnostics
Imports System.Security
Imports System.Text.RegularExpressions
Imports System.Threading

Module Example
    Const MaxTimeoutInSeconds As Integer = 3

    Public Sub Main()
        Dim pattern As String = "(a+)+$"    ' DO NOT REUSE THIS PATTERN.
        Dim rgx As New Regex(pattern, RegexOptions.IgnoreCase, TimeSpan.FromSeconds(1))
        Dim sw As Stopwatch = Nothing

        Dim inputs() As String = {"aa", "aaaa>",
                                   "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
                                   "aaaaaaaaaaaaaaaaaaaaaa>",
                                   "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa>"}

        For Each inputValue In inputs
            Console.WriteLine("Processing {0}", inputValue)
            Dim timedOut As Boolean = False
            Do
                Try
                    sw = Stopwatch.StartNew()
                    ' Display the result.
                    If rgx.IsMatch(inputValue) Then
                        sw.Stop()
                        Console.WriteLine("Valid: '{0}' ({1:ss\.fffffff} seconds)",
                                          inputValue, sw.Elapsed)
                    Else
                        sw.Stop()
                        Console.WriteLine("'{0}' is not a valid string. ({1:ss\.fffff} seconds)",
                                          inputValue, sw.Elapsed)
                    End If
                Catch e As RegexMatchTimeoutException
                    sw.Stop()
                    ' Display the elapsed time until the exception.
                    Console.WriteLine("Timeout with '{0}' after {1:ss\.fffff}",
                                      inputValue, sw.Elapsed)
                    Thread.Sleep(1500)       ' Pause for 1.5 seconds.

                    ' Increase the timeout interval and retry.
                    Dim timeout As TimeSpan = e.MatchTimeout.Add(TimeSpan.FromSeconds(1))
                    If timeout.TotalSeconds > MaxTimeoutInSeconds Then
                        Console.WriteLine("Maximum timeout interval of {0} seconds exceeded.",
                                          MaxTimeoutInSeconds)
                        timedOut = False
                    Else
                        Console.WriteLine("Changing the timeout interval to {0}",
                                          timeout)
                        rgx = New Regex(pattern, RegexOptions.IgnoreCase, timeout)
                        timedOut = True
                    End If
                End Try
            Loop While timedOut
            Console.WriteLine()
        Next
    End Sub
End Module
' The example displays output like the following:
'    Processing aa
'    Valid: 'aa' (00.0000779 seconds)
'    
'    Processing aaaa>
'    'aaaa>' is not a valid string. (00.00005 seconds)
'    
'    Processing aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
'    Valid: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' (00.0000043 seconds)
'    
'    Processing aaaaaaaaaaaaaaaaaaaaaa>
'    Timeout with 'aaaaaaaaaaaaaaaaaaaaaa>' after 01.00469
'    Changing the timeout interval to 00:00:02
'    Timeout with 'aaaaaaaaaaaaaaaaaaaaaa>' after 02.01202
'    Changing the timeout interval to 00:00:03
'    Timeout with 'aaaaaaaaaaaaaaaaaaaaaa>' after 03.01043
'    Maximum timeout interval of 3 seconds exceeded.
'    
'    Processing aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa>
'    Timeout with 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa>' after 03.01018
'    Maximum timeout interval of 3 seconds exceeded.

Grupos atômicosAtomic groups

O (?> elemento de linguagem de subexpressão ) suprime a retrocesso na subexpressão.The (?> subexpression) language element suppresses backtracking into the subexpression. Depois que ele for correspondido com êxito, ele não resultará em nenhuma parte de sua correspondência para o retrocesso posterior.Once it has successfully matched, it will not give up any part of its match to subsequent backtracking. Por exemplo, no padrão (?>\w*\d*)1 , se o 1 não puder ser correspondido, o não resultará em \d* nenhuma de suas correspondências, mesmo que isso signifique que isso permitiria que a 1 correspondência fosse bem-sucedida.For example, in the pattern (?>\w*\d*)1, if the 1 cannot be matched, the \d* will not give up any of its match even if that means it would allow the 1 to successfully match. Os grupos atômicos podem ajudar a evitar os problemas de desempenho associados às correspondências com falha.Atomic groups can help prevent the performance problems associated with failed matches.

O exemplo a seguir ilustra como suprimir o retrocesso melhora o desempenho quando quantificadores aninhados são usados.The following example illustrates how suppressing backtracking improves performance when using nested quantifiers. Ele mede o tempo necessário para que o mecanismo de expressão regular determine que uma cadeia de caracteres de entrada não corresponde a duas expressões regulares.It measures the time required for the regular expression engine to determine that an input string does not match two regular expressions. A primeira expressão regular usa o retrocesso para tentar corresponder uma cadeia de caracteres que contém uma ou mais ocorrências de um ou mais dígitos hexadecimais, seguidos por dois-pontos, seguido por um ou mais dígitos hexadecimais, seguidos por dois dois-pontos.The first regular expression uses backtracking to attempt to match a string that contains one or more occurrences of one or more hexadecimal digits, followed by a colon, followed by one or more hexadecimal digits, followed by two colons. A segunda expressão regular é idêntica à primeira, exceto que ela desabilita o retrocesso.The second regular expression is identical to the first, except that it disables backtracking. Como a saída do exemplo mostra, a melhora do desempenho resultante da desabilitação do retrocesso é significativa.As the output from the example shows, the performance improvement from disabling backtracking is significant.

using System;
using System.Diagnostics;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      string input = "b51:4:1DB:9EE1:5:27d60:f44:D4:cd:E:5:0A5:4a:D24:41Ad:";
      bool matched;
      Stopwatch sw;

      Console.WriteLine("With backtracking:");
      string backPattern = "^(([0-9a-fA-F]{1,4}:)*([0-9a-fA-F]{1,4}))*(::)$";
      sw = Stopwatch.StartNew();
      matched = Regex.IsMatch(input, backPattern);
      sw.Stop();
      Console.WriteLine("Match: {0} in {1}", Regex.IsMatch(input, backPattern), sw.Elapsed);
      Console.WriteLine();

      Console.WriteLine("Without backtracking:");
      string noBackPattern = "^((?>[0-9a-fA-F]{1,4}:)*(?>[0-9a-fA-F]{1,4}))*(::)$";
      sw = Stopwatch.StartNew();
      matched = Regex.IsMatch(input, noBackPattern);
      sw.Stop();
      Console.WriteLine("Match: {0} in {1}", Regex.IsMatch(input, noBackPattern), sw.Elapsed);
   }
}
// The example displays output like the following:
//       With backtracking:
//       Match: False in 00:00:27.4282019
//
//       Without backtracking:
//       Match: False in 00:00:00.0001391
Imports System.Diagnostics
Imports System.Text.RegularExpressions

Module Example
    Public Sub Main()
        Dim input As String = "b51:4:1DB:9EE1:5:27d60:f44:D4:cd:E:5:0A5:4a:D24:41Ad:"
        Dim matched As Boolean
        Dim sw As Stopwatch

        Console.WriteLine("With backtracking:")
        Dim backPattern As String = "^(([0-9a-fA-F]{1,4}:)*([0-9a-fA-F]{1,4}))*(::)$"
        sw = Stopwatch.StartNew()
        matched = Regex.IsMatch(input, backPattern)
        sw.Stop()
        Console.WriteLine("Match: {0} in {1}", Regex.IsMatch(input, backPattern), sw.Elapsed)
        Console.WriteLine()

        Console.WriteLine("Without backtracking:")
        Dim noBackPattern As String = "^((?>[0-9a-fA-F]{1,4}:)*(?>[0-9a-fA-F]{1,4}))*(::)$"
        sw = Stopwatch.StartNew()
        matched = Regex.IsMatch(input, noBackPattern)
        sw.Stop()
        Console.WriteLine("Match: {0} in {1}", Regex.IsMatch(input, noBackPattern), sw.Elapsed)
    End Sub
End Module
' The example displays the following output:
'       With backtracking:
'       Match: False in 00:00:27.4282019
'       
'       Without backtracking:
'       Match: False in 00:00:00.0001391

Asserções lookbehindLookbehind Assertions

O .NET inclui dois elementos de linguagem, (?<= subexpressão ) e (?<! subexpressão ) , que correspondem ao caractere ou caracteres anteriores na cadeia de caracteres de entrada..NET includes two language elements, (?<=subexpression) and (?<!subexpression), that match the previous character or characters in the input string. Ambos os elementos de linguagem são asserções de largura zero, ou seja, eles determinam se o caractere ou os caracteres que precedem imediatamente o caractere atual podem ser correspondidos pela subexpressão, sem avanço ou retrocesso.Both language elements are zero-width assertions; that is, they determine whether the character or characters that immediately precede the current character can be matched by subexpression, without advancing or backtracking.

(?<=subexpressão ) é uma asserção lookbehind positiva; ou seja, o caractere ou os caracteres antes da posição atual devem corresponder à subexpressão.(?<= subexpression ) is a positive lookbehind assertion; that is, the character or characters before the current position must match subexpression. (?<!subexpressão ) é uma asserção lookbehind negativa; ou seja, o caractere ou os caracteres antes da posição atual não devem corresponder à subexpressão.(?<!subexpression) is a negative lookbehind assertion; that is, the character or characters before the current position must not match subexpression. As asserções lookbehind positivas e negativas são mais úteis quando a subexpressão é um subconjunto da subexpressão anterior.Both positive and negative lookbehind assertions are most useful when subexpression is a subset of the previous subexpression.

O exemplo a seguir usa dois padrões equivalentes à expressão regular que validam o nome de usuário em um endereço de email.The following example uses two equivalent regular expression patterns that validate the user name in an email address. O primeiro padrão está sujeito a baixo desempenho devido ao retrocesso excessivo.The first pattern is subject to poor performance because of excessive backtracking. O segundo padrão modifica a primeira expressão regular ao substituir um quantificador aninhado por uma asserção lookbehind positiva.The second pattern modifies the first regular expression by replacing a nested quantifier with a positive lookbehind assertion. A saída do exemplo exibe, o tempo de execução do método Regex.IsMatch.The output from the example displays the execution time of the Regex.IsMatch method.

using System;
using System.Diagnostics;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      Stopwatch sw;
      string input = "test@contoso.com";
      bool result;

      string pattern = @"^[0-9A-Z]([-.\w]*[0-9A-Z])?@";
      sw = Stopwatch.StartNew();
      result = Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase);
      sw.Stop();
      Console.WriteLine("Match: {0} in {1}", result, sw.Elapsed);

      string behindPattern = @"^[0-9A-Z][-.\w]*(?<=[0-9A-Z])@";
      sw = Stopwatch.StartNew();
      result = Regex.IsMatch(input, behindPattern, RegexOptions.IgnoreCase);
      sw.Stop();
      Console.WriteLine("Match with Lookbehind: {0} in {1}", result, sw.Elapsed);
   }
}
// The example displays output similar to the following:
//       Match: True in 00:00:00.0017549
//       Match with Lookbehind: True in 00:00:00.0000659
Module Example
    Public Sub Main()
        Dim sw As Stopwatch
        Dim input As String = "test@contoso.com"
        Dim result As Boolean

        Dim pattern As String = "^[0-9A-Z]([-.\w]*[0-9A-Z])?@"
        sw = Stopwatch.StartNew()
        result = Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase)
        sw.Stop()
        Console.WriteLine("Match: {0} in {1}", result, sw.Elapsed)

        Dim behindPattern As String = "^[0-9A-Z][-.\w]*(?<=[0-9A-Z])@"
        sw = Stopwatch.StartNew()
        result = Regex.IsMatch(input, behindPattern, RegexOptions.IgnoreCase)
        sw.Stop()
        Console.WriteLine("Match with Lookbehind: {0} in {1}", result, sw.Elapsed)
    End Sub
End Module
' The example displays output similar to the following:
'       Match: True in 00:00:00.0017549
'       Match with Lookbehind: True in 00:00:00.0000659

O primeiro padrão de expressão regular, ^[0-9A-Z]([-.\w]*[0-9A-Z])*@, é definido como mostrado na tabela a seguir.The first regular expression pattern, ^[0-9A-Z]([-.\w]*[0-9A-Z])*@, is defined as shown in the following table.

PadrãoPattern DescriçãoDescription
^ Começa a correspondência no início da cadeia de caracteres.Start the match at the beginning of the string.
[0-9A-Z] Corresponde a um caractere alfanumérico.Match an alphanumeric character. Essa comparação não diferencia maiúsculas de minúsculas porque o método Regex.IsMatch é chamado com a opção RegexOptions.IgnoreCase.This comparison is case-insensitive, because the Regex.IsMatch method is called with the RegexOptions.IgnoreCase option.
[-.\w]* Corresponde a zero, uma ou mais ocorrências de um hífen, ponto ou caractere de palavra.Match zero, one, or more occurrences of a hyphen, period, or word character.
[0-9A-Z] Corresponde a um caractere alfanumérico.Match an alphanumeric character.
([-.\w]*[0-9A-Z])* Corresponde a zero ou mais ocorrências da combinação de zero ou mais hífens, pontos ou caracteres de palavra, seguidos por um caractere alfanumérico.Match zero or more occurrences of the combination of zero or more hyphens, periods, or word characters, followed by an alphanumeric character. Este é o primeiro grupo de captura.This is the first capturing group.
@ Corresponde a um sinal ("@").Match an at sign ("@").

O segundo padrão de expressão regular, ^[0-9A-Z][-.\w]*(?<=[0-9A-Z])@, usa uma asserção lookbehind positiva.The second regular expression pattern, ^[0-9A-Z][-.\w]*(?<=[0-9A-Z])@, uses a positive lookbehind assertion. Ele é definido conforme mostrado na tabela a seguir.It is defined as shown in the following table.

PadrãoPattern DescriçãoDescription
^ Começa a correspondência no início da cadeia de caracteres.Start the match at the beginning of the string.
[0-9A-Z] Corresponde a um caractere alfanumérico.Match an alphanumeric character. Essa comparação não diferencia maiúsculas de minúsculas porque o método Regex.IsMatch é chamado com a opção RegexOptions.IgnoreCase.This comparison is case-insensitive, because the Regex.IsMatch method is called with the RegexOptions.IgnoreCase option.
[-.\w]* Corresponde a zero ou mais ocorrências de um hífen, ponto ou caractere de palavra.Match zero or more occurrences of a hyphen, period, or word character.
(?<=[0-9A-Z]) Examina de volta o último caractere correspondente e continua a correspondência se ele é alfanumérico.Look back at the last matched character and continue the match if it is alphanumeric. Observe que os caracteres alfanuméricos são um subconjunto do conjunto que consiste em pontos, hífens e todos os caracteres de palavra.Note that alphanumeric characters are a subset of the set that consists of periods, hyphens, and all word characters.
@ Corresponde a um sinal ("@").Match an at sign ("@").

Asserções lookaheadLookahead Assertions

O .NET inclui dois elementos de linguagem, (?= subexpressão ) e (?! subexpressão ) , que correspondem ao próximo caractere ou caracteres na cadeia de caracteres de entrada..NET includes two language elements, (?=subexpression) and (?!subexpression), that match the next character or characters in the input string. Ambos os elementos de linguagem são asserções de largura zero, ou seja, eles determinam se o caractere ou os caracteres que seguem imediatamente o caractere atual podem ser correspondidos pela subexpressão, sem avanço ou retrocesso.Both language elements are zero-width assertions; that is, they determine whether the character or characters that immediately follow the current character can be matched by subexpression, without advancing or backtracking.

(?=subexpressão ) é uma asserção de antecipação positiva; ou seja, o caractere ou os caracteres após a posição atual devem corresponder à subexpressão.(?= subexpression ) is a positive lookahead assertion; that is, the character or characters after the current position must match subexpression. (?!subexpressão ) é uma asserção de antecipação negativa; ou seja, o caractere ou os caracteres após a posição atual não devem corresponder à subexpressão.(?!subexpression) is a negative lookahead assertion; that is, the character or characters after the current position must not match subexpression. As declarações de lookahead positiva e negativa são mais úteis quando a subexpressão é um subconjunto da próxima subexpressão.Both positive and negative lookahead assertions are most useful when subexpression is a subset of the next subexpression.

O exemplo a seguir usa dois padrões de expressão regular equivalentes que validam um nome de tipo totalmente qualificado.The following example uses two equivalent regular expression patterns that validate a fully qualified type name. O primeiro padrão está sujeito a baixo desempenho devido ao retrocesso excessivo.The first pattern is subject to poor performance because of excessive backtracking. O segundo modifica a primeira expressão regular ao substituir um quantificador aninhado por uma asserção lookahead positiva.The second modifies the first regular expression by replacing a nested quantifier with a positive lookahead assertion. A saída do exemplo exibe, o tempo de execução do método Regex.IsMatch.The output from the example displays the execution time of the Regex.IsMatch method.

using System;
using System.Diagnostics;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      string input = "aaaaaaaaaaaaaaaaaaaaaa.";
      bool result;
      Stopwatch sw;

      string pattern = @"^(([A-Z]\w*)+\.)*[A-Z]\w*$";
      sw = Stopwatch.StartNew();
      result = Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase);
      sw.Stop();
      Console.WriteLine("{0} in {1}", result, sw.Elapsed);

      string aheadPattern = @"^((?=[A-Z])\w+\.)*[A-Z]\w*$";
      sw = Stopwatch.StartNew();
      result = Regex.IsMatch(input, aheadPattern, RegexOptions.IgnoreCase);
      sw.Stop();
      Console.WriteLine("{0} in {1}", result, sw.Elapsed);
   }
}
// The example displays the following output:
//       False in 00:00:03.8003793
//       False in 00:00:00.0000866
Imports System.Diagnostics
Imports System.Text.RegularExpressions

Module Example
    Public Sub Main()
        Dim input As String = "aaaaaaaaaaaaaaaaaaaaaa."
        Dim result As Boolean
        Dim sw As Stopwatch

        Dim pattern As String = "^(([A-Z]\w*)+\.)*[A-Z]\w*$"
        sw = Stopwatch.StartNew()
        result = Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase)
        sw.Stop()
        Console.WriteLine("{0} in {1}", result, sw.Elapsed)

        Dim aheadPattern As String = "^((?=[A-Z])\w+\.)*[A-Z]\w*$"
        sw = Stopwatch.StartNew()
        result = Regex.IsMatch(input, aheadPattern, RegexOptions.IgnoreCase)
        sw.Stop()
        Console.WriteLine("{0} in {1}", result, sw.Elapsed)
    End Sub
End Module
' The example displays the following output:
'       False in 00:00:03.8003793
'       False in 00:00:00.0000866

O primeiro padrão de expressão regular, ^(([A-Z]\w*)+\.)*[A-Z]\w*$, é definido como mostrado na tabela a seguir.The first regular expression pattern, ^(([A-Z]\w*)+\.)*[A-Z]\w*$, is defined as shown in the following table.

PadrãoPattern DescriçãoDescription
^ Começa a correspondência no início da cadeia de caracteres.Start the match at the beginning of the string.
([A-Z]\w*)+\. Corresponde a um caractere alfabético (A-Z) seguido por zero ou mais caracteres de palavra uma ou mais vezes, seguidos de um ponto.Match an alphabetical character (A-Z) followed by zero or more word characters one or more times, followed by a period. Essa comparação não diferencia maiúsculas de minúsculas porque o método Regex.IsMatch é chamado com a opção RegexOptions.IgnoreCase.This comparison is case-insensitive, because the Regex.IsMatch method is called with the RegexOptions.IgnoreCase option.
(([A-Z]\w*)+\.)* Corresponde ao padrão anterior zero vezes ou mais.Match the previous pattern zero or more times.
[A-Z]\w* Corresponder a um caractere alfabético seguido por zero ou mais caracteres de palavra.Match an alphabetical character followed by zero or more word characters.
$ Finalizar a correspondência no final da cadeia de caracteres de entrada.End the match at the end of the input string.

O segundo padrão de expressão regular, ^((?=[A-Z])\w+\.)*[A-Z]\w*$, usa uma asserção lookahead positiva.The second regular expression pattern, ^((?=[A-Z])\w+\.)*[A-Z]\w*$, uses a positive lookahead assertion. Ele é definido conforme mostrado na tabela a seguir.It is defined as shown in the following table.

PadrãoPattern DescriçãoDescription
^ Começa a correspondência no início da cadeia de caracteres.Start the match at the beginning of the string.
(?=[A-Z]) Examine além do primeiro caractere e continue a correspondência se ele for alfabético (A-Z).Look ahead to the first character and continue the match if it is alphabetical (A-Z). Essa comparação não diferencia maiúsculas de minúsculas porque o método Regex.IsMatch é chamado com a opção RegexOptions.IgnoreCase.This comparison is case-insensitive, because the Regex.IsMatch method is called with the RegexOptions.IgnoreCase option.
\w+\. Corresponde a um ou mais caracteres de palavra seguidos por um ponto.Match one or more word characters followed by a period.
((?=[A-Z])\w+\.)* Corresponde ao padrão de um ou mais caracteres de palavra seguidos por um ponto zero ou mais vezes.Match the pattern of one or more word characters followed by a period zero or more times. O caractere de palavra inicial deve ser alfabético.The initial word character must be alphabetical.
[A-Z]\w* Corresponder a um caractere alfabético seguido por zero ou mais caracteres de palavra.Match an alphabetical character followed by zero or more word characters.
$ Finalizar a correspondência no final da cadeia de caracteres de entrada.End the match at the end of the input string.

Veja tambémSee also