Detalhes do comportamento de expressão regular

O mecanismo de expressão regular .NET é um matcher de expressão regular de backtracking que incorpora um mecanismo tradicional de autômato finito (NFA) não determinístico, como o usado por Perl, Python, Emacs e Tcl. Isso o distingue de motores Deterministic Finite Automaton (DFA) de expressão regular mais rápidos, mas mais limitados, como os encontrados em awk, egrep ou lex. Isso também o distingue de POSIX NFAs padronizados, mas mais lentos. A seção a seguir descreve os três tipos de mecanismos de expressão regular e explica por que expressões regulares no .NET são implementadas usando um mecanismo NFA tradicional.

Benefícios do motor NFA

Quando os mecanismos DFA executam a correspondência de padrões, sua ordem de processamento é orientada pela cadeia de caracteres de entrada. O mecanismo começa no início da cadeia de caracteres de entrada e prossegue sequencialmente para determinar se o próximo caractere corresponde ao padrão de expressão regular. Eles podem garantir que correspondem à maior corda possível. Como eles nunca testam o mesmo caractere duas vezes, os mecanismos DFA não suportam backtracking. No entanto, como um mecanismo DFA contém apenas estado finito, ele não pode corresponder a um padrão com referências de retorno e, como não constrói uma expansão explícita, não pode capturar subexpressões.

Ao contrário dos mecanismos DFA, quando os mecanismos NFA tradicionais executam a correspondência de padrões, sua ordem de processamento é orientada pelo padrão de expressão regular. À medida que processa um elemento linguístico específico, o motor usa correspondência gananciosa; ou seja, ele corresponde o máximo possível da cadeia de caracteres de entrada. Mas ele também salva seu estado depois de combinar com sucesso uma subexpressão. Se uma partida eventualmente falhar, o mecanismo pode retornar a um estado salvo para que possa tentar correspondências adicionais. Esse processo de abandonar uma correspondência de subexpressão bem-sucedida para que elementos de linguagem posteriores na expressão regular também possam corresponder é conhecido como backtracking. Os mecanismos NFA usam backtracking para testar todas as expansões possíveis de uma expressão regular em uma ordem específica e aceitar a primeira correspondência. Como um mecanismo NFA tradicional constrói uma expansão específica da expressão regular para uma partida bem-sucedida, ele pode capturar correspondências de subexpressão e referências de retorno correspondentes. No entanto, como um NFA tradicional retrocede, ele pode visitar o mesmo estado várias vezes se chegar ao estado por caminhos diferentes. Como resultado, pode funcionar exponencialmente lentamente na pior das hipóteses. Como um mecanismo NFA tradicional aceita a primeira correspondência encontrada, ele também pode deixar outras correspondências (possivelmente mais longas) desconhecidas.

Os motores POSIX NFA são como os motores NFA tradicionais, exceto que eles continuam a recuar até que possam garantir que encontraram a partida mais longa possível. Como resultado, um mecanismo POSIX NFA é mais lento do que um mecanismo NFA tradicional, e quando você usa um mecanismo POSIX NFA, não pode favorecer uma partida mais curta em vez de uma mais longa alterando a ordem da pesquisa de backtracking.

Os mecanismos NFA tradicionais são favorecidos pelos programadores porque oferecem maior controle sobre a correspondência de cadeias de caracteres do que os mecanismos DFA ou POSIX NFA. Embora, na pior das hipóteses, eles possam ser executados lentamente, você pode orientá-los a encontrar correspondências em tempo linear ou polinomial usando padrões que reduzem ambiguidades e limitam o retrocesso. Em outras palavras, embora os mecanismos NFA troquem o desempenho por potência e flexibilidade, na maioria dos casos eles oferecem um desempenho bom a aceitável se uma expressão regular for bem escrita e evitar casos em que o backtracking degrada o desempenho exponencialmente.

Nota

Para obter informações sobre a penalidade de desempenho causada pelo retrocesso excessivo e maneiras de criar uma expressão regular para contorná-los, consulte Retrocesso.

Recursos do mecanismo .NET

Para aproveitar os benefícios de um mecanismo NFA tradicional, o mecanismo de expressão regular .NET inclui um conjunto completo de construções para permitir que os programadores orientem o mecanismo de backtracking. Essas construções podem ser usadas para encontrar correspondências mais rapidamente ou para favorecer expansões específicas em detrimento de outras.

Outros recursos do mecanismo de expressão regular .NET incluem o seguinte:

  • Quantificadores preguiçosos: ??, *?, +?, {n,m.}? Essas construções dizem ao mecanismo de backtracking para pesquisar o número mínimo de repetições primeiro. Em contraste, quantificadores gananciosos comuns tentam corresponder ao número máximo de repetições primeiro. O exemplo a seguir ilustra a diferença entre os dois. Uma expressão regular corresponde a uma frase que termina em um número, e um grupo de captura destina-se a extrair esse número. A expressão .+(\d+)\. regular inclui o quantificador ganancioso .+, que faz com que o mecanismo de expressão regular capture apenas o último dígito do número. Em contraste, a expressão .+?(\d+)\. regular inclui o quantificador preguiçoso .+?, que faz com que o mecanismo de expressão regular capture o número inteiro.

    using System;
    using System.Text.RegularExpressions;
    
    public class Example
    {
        public static void Main()
        {
            string greedyPattern = @".+(\d+)\.";
            string lazyPattern = @".+?(\d+)\.";
            string input = "This sentence ends with the number 107325.";
            Match match;
    
            // Match using greedy quantifier .+.
            match = Regex.Match(input, greedyPattern);
            if (match.Success)
                Console.WriteLine("Number at end of sentence (greedy): {0}",
                                  match.Groups[1].Value);
            else
                Console.WriteLine("{0} finds no match.", greedyPattern);
    
            // Match using lazy quantifier .+?.
            match = Regex.Match(input, lazyPattern);
            if (match.Success)
                Console.WriteLine("Number at end of sentence (lazy): {0}",
                                  match.Groups[1].Value);
            else
                Console.WriteLine("{0} finds no match.", lazyPattern);
        }
    }
    // The example displays the following output:
    //       Number at end of sentence (greedy): 5
    //       Number at end of sentence (lazy): 107325
    
    Imports System.Text.RegularExpressions
    
    Module Example
        Public Sub Main()
            Dim greedyPattern As String = ".+(\d+)\."
            Dim lazyPattern As String = ".+?(\d+)\."
            Dim input As String = "This sentence ends with the number 107325."
            Dim match As Match
    
            ' Match using greedy quantifier .+.
            match = Regex.Match(input, greedyPattern)
            If match.Success Then
                Console.WriteLine("Number at end of sentence (greedy): {0}",
                                  match.Groups(1).Value)
            Else
                Console.WriteLine("{0} finds no match.", greedyPattern)
            End If
    
            ' Match using lazy quantifier .+?.
            match = Regex.Match(input, lazyPattern)
            If match.Success Then
                Console.WriteLine("Number at end of sentence (lazy): {0}",
                                  match.Groups(1).Value)
            Else
                Console.WriteLine("{0} finds no match.", lazyPattern)
            End If
        End Sub
    End Module
    ' The example displays the following output:
    '       Number at end of sentence (greedy): 5
    '       Number at end of sentence (lazy): 107325
    

    As versões gananciosas e preguiçosas desta expressão regular são definidas como mostrado na tabela a seguir:

    Padrão Description
    .+ (quantificador ganancioso) Corresponder pelo menos uma ocorrência de qualquer personagem. Isso faz com que o mecanismo de expressão regular corresponda a toda a cadeia de caracteres e, em seguida, retroceda conforme necessário para corresponder ao restante do padrão.
    .+? (quantificador preguiçoso) Corresponda pelo menos uma ocorrência de qualquer personagem, mas corresponda o mínimo possível.
    (\d+) Corresponder pelo menos um caractere numérico e atribuí-lo ao primeiro grupo de captura.
    \. Corresponda a um ponto.

    Para obter mais informações sobre quantificadores preguiçosos, consulte Quantifiers.

  • Olhar positivo: (?=subexpressão). Esse recurso permite que o mecanismo de backtracking retorne ao mesmo local no texto depois de corresponder a uma subexpressão. É útil para pesquisar ao longo do texto, verificando vários padrões que começam a partir da mesma posição. Ele também permite que o mecanismo verifique se existe uma substring no final da correspondência sem incluir a substring no texto correspondente. O exemplo a seguir usa o olhar positivo para extrair as palavras em uma frase que não são seguidas por símbolos de pontuação.

    using System;
    using System.Text.RegularExpressions;
    
    public class Example
    {
        public static void Main()
        {
            string pattern = @"\b[A-Z]+\b(?=\P{P})";
            string input = "If so, what comes next?";
            foreach (Match match in Regex.Matches(input, pattern, RegexOptions.IgnoreCase))
                Console.WriteLine(match.Value);
        }
    }
    // The example displays the following output:
    //       If
    //       what
    //       comes
    
    Imports System.Text.RegularExpressions
    
    Module Example
        Public Sub Main()
            Dim pattern As String = "\b[A-Z]+\b(?=\P{P})"
            Dim input As String = "If so, what comes next?"
            For Each match As Match In Regex.Matches(input, pattern, RegexOptions.IgnoreCase)
                Console.WriteLine(match.Value)
            Next
        End Sub
    End Module
    ' The example displays the following output:
    '       If
    '       what
    '       comes
    

    A expressão \b[A-Z]+\b(?=\P{P}) regular é definida conforme mostrado na tabela a seguir.

    Padrão Description
    \b Comece a partida com um limite de palavras.
    [A-Z]+ Corresponder a qualquer caractere alfabético uma ou mais vezes. Como o Regex.Matches método é chamado com a RegexOptions.IgnoreCase opção, a comparação não diferencia maiúsculas de minúsculas.
    \b Termine a partida com um limite de palavras.
    (?=\P{P}) Observe em frente para determinar se o próximo caractere é um símbolo de pontuação. Se não for, a partida é bem-sucedida.

    Para obter mais informações sobre asserções positivas de lookahead, consulte Agrupando construções.

  • Olhar negativo: (?!subexpressão). Esse recurso adiciona a capacidade de corresponder a uma expressão somente se uma subexpressão não corresponder. Isso é poderoso para podar uma pesquisa, porque muitas vezes é mais simples fornecer uma expressão para um caso que deve ser eliminado do que uma expressão para casos que devem ser incluídos. Por exemplo, é difícil escrever uma expressão para palavras que não comecem com "não". O exemplo a seguir usa lookahead negativo para excluí-los.

    using System;
    using System.Text.RegularExpressions;
    
    public class Example
    {
        public static void Main()
        {
            string pattern = @"\b(?!non)\w+\b";
            string input = "Nonsense is not always non-functional.";
            foreach (Match match in Regex.Matches(input, pattern, RegexOptions.IgnoreCase))
                Console.WriteLine(match.Value);
        }
    }
    // The example displays the following output:
    //       is
    //       not
    //       always
    //       functional
    
    Imports System.Text.RegularExpressions
    
    Module Example
        Public Sub Main()
            Dim pattern As String = "\b(?!non)\w+\b"
            Dim input As String = "Nonsense is not always non-functional."
            For Each match As Match In Regex.Matches(input, pattern, RegexOptions.IgnoreCase)
                Console.WriteLine(match.Value)
            Next
        End Sub
    End Module
    ' The example displays the following output:
    '       is
    '       not
    '       always
    '       functional
    

    O padrão \b(?!non)\w+\b de expressão regular é definido conforme mostrado na tabela a seguir.

    Padrão Description
    \b Comece a partida com um limite de palavras.
    (?!non) Procure garantir que a cadeia de caracteres atual não comece com "non". Se isso acontecer, a partida falha.
    (\w+) Corresponder a um ou mais caracteres de palavra.
    \b Termine a partida com um limite de palavras.

    Para obter mais informações sobre asserções de lookahead negativas, consulte Agrupando construções.

  • Avaliação condicional: (?(expressão)sim|não) e(?( nome)sim|não), onde expressão é uma subexpressão a corresponder, nome é o nome de um grupo de captura, sim é a cadeia de caracteres a corresponder se a expressão for correspondida ou nome for um grupo capturado válido, não vazio, e não é a subexpressão a corresponder se expressão não corresponde ou o nome não é um grupo capturado válido e não vazio. Esse recurso permite que o mecanismo pesquise usando mais de um padrão alternativo, dependendo do resultado de uma correspondência de subexpressão anterior ou do resultado de uma asserção de largura zero. Isso permite uma forma mais poderosa de backreference que permite, por exemplo, a correspondência de uma subexpressão com base na correspondência de uma subexpressão anterior. A expressão regular no exemplo a seguir corresponde a parágrafos destinados ao uso público e interno. Os parágrafos destinados apenas para uso interno começam com uma <PRIVATE> tag. O padrão ^(?<Pvt>\<PRIVATE\>\s)?(?(Pvt)((\w+\p{P}?\s)+)|((\w+\p{P}?\s)+))\r?$ de expressão regular usa avaliação condicional para atribuir o conteúdo de parágrafos destinados ao público e para uso interno a grupos de captura separados. Estes parágrafos podem então ser tratados de forma diferente.

    using System;
    using System.Text.RegularExpressions;
    
    public class Example
    {
        public static void Main()
        {
            string input = "<PRIVATE> This is not for public consumption." + Environment.NewLine +
                           "But this is for public consumption." + Environment.NewLine +
                           "<PRIVATE> Again, this is confidential.\n";
            string pattern = @"^(?<Pvt>\<PRIVATE\>\s)?(?(Pvt)((\w+\p{P}?\s)+)|((\w+\p{P}?\s)+))\r?$";
            string publicDocument = null, privateDocument = null;
    
            foreach (Match match in Regex.Matches(input, pattern, RegexOptions.Multiline))
            {
                if (match.Groups[1].Success)
                {
                    privateDocument += match.Groups[1].Value + "\n";
                }
                else
                {
                    publicDocument += match.Groups[3].Value + "\n";
                    privateDocument += match.Groups[3].Value + "\n";
                }
            }
    
            Console.WriteLine("Private Document:");
            Console.WriteLine(privateDocument);
            Console.WriteLine("Public Document:");
            Console.WriteLine(publicDocument);
        }
    }
    // The example displays the following output:
    //    Private Document:
    //    This is not for public consumption.
    //    But this is for public consumption.
    //    Again, this is confidential.
    //
    //    Public Document:
    //    But this is for public consumption.
    
    Imports System.Text.RegularExpressions
    
    Module Example
        Public Sub Main()
            Dim input As String = "<PRIVATE> This is not for public consumption." + vbCrLf + _
                                  "But this is for public consumption." + vbCrLf + _
                                  "<PRIVATE> Again, this is confidential." + vbCrLf
            Dim pattern As String = "^(?<Pvt>\<PRIVATE\>\s)?(?(Pvt)((\w+\p{P}?\s)+)|((\w+\p{P}?\s)+))\r?$"
            Dim publicDocument As String = Nothing
            Dim privateDocument As String = Nothing
    
            For Each match As Match In Regex.Matches(input, pattern, RegexOptions.Multiline)
                If match.Groups(1).Success Then
                    privateDocument += match.Groups(1).Value + vbCrLf
                Else
                    publicDocument += match.Groups(3).Value + vbCrLf
                    privateDocument += match.Groups(3).Value + vbCrLf
                End If
            Next
    
            Console.WriteLine("Private Document:")
            Console.WriteLine(privateDocument)
            Console.WriteLine("Public Document:")
            Console.WriteLine(publicDocument)
        End Sub
    End Module
    ' The example displays the following output:
    '    Private Document:
    '    This is not for public consumption.
    '    But this is for public consumption.
    '    Again, this is confidential.
    '    
    '    Public Document:
    '    But this is for public consumption.
    

    O padrão de expressão regular é definido conforme mostrado na tabela a seguir.

    Padrão Description
    ^ Comece a partida no início de uma linha.
    (?<Pvt>\<PRIVATE\>\s)? Corresponder a zero ou uma ocorrência da cadeia de caracteres <PRIVATE> seguida por um caractere de espaço em branco. Atribua a correspondência a um grupo de captura chamado Pvt.
    (?(Pvt)((\w+\p{P}?\s)+) Se o Pvt grupo de captura existir, corresponda a uma ou mais ocorrências de um ou mais caracteres de palavra seguidos por zero ou um separador de pontuação seguido por um caractere de espaço em branco. Atribua a substring ao primeiro grupo de captura.
    |((\w+\p{P}?\s)+)) Se o Pvt grupo de captura não existir, corresponda a uma ou mais ocorrências de um ou mais caracteres de palavra seguidos por zero ou um separador de pontuação seguido por um caractere de espaço em branco. Atribua a substring ao terceiro grupo de captura.
    \r?$ Corresponder ao fim de uma linha ou ao fim da cadeia de caracteres.

    Para obter mais informações sobre avaliação condicional, consulte Construções de alternância.

  • Equilibrando definições de grupo: (?<subexpressão) name1-name2.> Esse recurso permite que o mecanismo de expressão regular acompanhe construções aninhadas, como parênteses ou colchetes de abertura e fechamento. Para obter um exemplo, consulte Agrupando construções.

  • Grupos atômicos: (?>subexpressão). Esse recurso permite que o mecanismo de backtracking garanta que uma subexpressão corresponda apenas à primeira correspondência encontrada para essa subexpressão, como se a expressão estivesse sendo executada independentemente de sua expressão que a contém. Se você não usar essa construção, o rastreamento de pesquisas da expressão maior pode alterar o comportamento de uma subexpressão. Por exemplo, a expressão (a+)\w regular corresponde a um ou mais caracteres "a", juntamente com um caractere de palavra que segue a sequência de caracteres "a" e atribui a sequência de caracteres "a" ao primeiro grupo de captura. No entanto, se o caractere final da cadeia de caracteres de entrada também for um "a", ele será correspondido \w pelo elemento de idioma e não será incluído no grupo capturado.

    using System;
    using System.Text.RegularExpressions;
    
    public class Example
    {
        public static void Main()
        {
            string[] inputs = { "aaaaa", "aaaaab" };
            string backtrackingPattern = @"(a+)\w";
            Match match;
    
            foreach (string input in inputs)
            {
                Console.WriteLine("Input: {0}", input);
                match = Regex.Match(input, backtrackingPattern);
                Console.WriteLine("   Pattern: {0}", backtrackingPattern);
                if (match.Success)
                {
                    Console.WriteLine("      Match: {0}", match.Value);
                    Console.WriteLine("      Group 1: {0}", match.Groups[1].Value);
                }
                else
                {
                    Console.WriteLine("      Match failed.");
                }
            }
            Console.WriteLine();
        }
    }
    // The example displays the following output:
    //       Input: aaaaa
    //          Pattern: (a+)\w
    //             Match: aaaaa
    //             Group 1: aaaa
    //       Input: aaaaab
    //          Pattern: (a+)\w
    //             Match: aaaaab
    //             Group 1: aaaaa
    
    Imports System.Text.RegularExpressions
    
    Module Example
        Public Sub Main()
            Dim inputs() As String = {"aaaaa", "aaaaab"}
            Dim backtrackingPattern As String = "(a+)\w"
            Dim match As Match
    
            For Each input As String In inputs
                Console.WriteLine("Input: {0}", input)
                match = Regex.Match(input, backtrackingPattern)
                Console.WriteLine("   Pattern: {0}", backtrackingPattern)
                If match.Success Then
                    Console.WriteLine("      Match: {0}", match.Value)
                    Console.WriteLine("      Group 1: {0}", match.Groups(1).Value)
                Else
                    Console.WriteLine("      Match failed.")
                End If
            Next
            Console.WriteLine()
        End Sub
    End Module
    ' The example displays the following output:
    '       Input: aaaaa
    '          Pattern: (a+)\w
    '             Match: aaaaa
    '             Group 1: aaaa
    '       Input: aaaaab
    '          Pattern: (a+)\w
    '             Match: aaaaab
    '             Group 1: aaaaa
    

    A expressão ((?>a+))\w regular impede esse comportamento. Como todos os caracteres "a" consecutivos são combinados sem retrocesso, o primeiro grupo de captura inclui todos os caracteres "a" consecutivos. Se os caracteres "a" não forem seguidos por pelo menos mais um caractere além de "a", a correspondência falhará.

    using System;
    using System.Text.RegularExpressions;
    
    public class Example
    {
        public static void Main()
        {
            string[] inputs = { "aaaaa", "aaaaab" };
            string nonbacktrackingPattern = @"((?>a+))\w";
            Match match;
    
            foreach (string input in inputs)
            {
                Console.WriteLine("Input: {0}", input);
                match = Regex.Match(input, nonbacktrackingPattern);
                Console.WriteLine("   Pattern: {0}", nonbacktrackingPattern);
                if (match.Success)
                {
                    Console.WriteLine("      Match: {0}", match.Value);
                    Console.WriteLine("      Group 1: {0}", match.Groups[1].Value);
                }
                else
                {
                    Console.WriteLine("      Match failed.");
                }
            }
            Console.WriteLine();
        }
    }
    // The example displays the following output:
    //       Input: aaaaa
    //          Pattern: ((?>a+))\w
    //             Match failed.
    //       Input: aaaaab
    //          Pattern: ((?>a+))\w
    //             Match: aaaaab
    //             Group 1: aaaaa
    
    Imports System.Text.RegularExpressions
    
    Module Example
        Public Sub Main()
            Dim inputs() As String = {"aaaaa", "aaaaab"}
            Dim nonbacktrackingPattern As String = "((?>a+))\w"
            Dim match As Match
    
            For Each input As String In inputs
                Console.WriteLine("Input: {0}", input)
                match = Regex.Match(input, nonbacktrackingPattern)
                Console.WriteLine("   Pattern: {0}", nonbacktrackingPattern)
                If match.Success Then
                    Console.WriteLine("      Match: {0}", match.Value)
                    Console.WriteLine("      Group 1: {0}", match.Groups(1).Value)
                Else
                    Console.WriteLine("      Match failed.")
                End If
            Next
            Console.WriteLine()
        End Sub
    End Module
    ' The example displays the following output:
    '       Input: aaaaa
    '          Pattern: ((?>a+))\w
    '             Match failed.
    '       Input: aaaaab
    '          Pattern: ((?>a+))\w
    '             Match: aaaaab
    '             Group 1: aaaaa
    

    Para obter mais informações sobre grupos atômicos, consulte Agrupando construções.

  • Correspondência da direita para a esquerda, que é especificada fornecendo a RegexOptions.RightToLeft opção para um Regex construtor de classe ou método de correspondência de instância estática. Este recurso é útil ao pesquisar da direita para a esquerda em vez de da esquerda para a direita, ou nos casos em que é mais eficiente começar uma correspondência na parte direita do padrão em vez da esquerda. Como o exemplo a seguir ilustra, usar a correspondência da direita para a esquerda pode mudar o comportamento de quantificadores gananciosos. O exemplo realiza duas buscas por uma frase que termina em um número. A pesquisa da esquerda para a direita que usa o quantificador ganancioso + corresponde a um dos seis dígitos da frase, enquanto a pesquisa da direita para a esquerda corresponde a todos os seis dígitos. Para obter uma descrição do padrão de expressão regular, consulte o exemplo que ilustra quantificadores preguiçosos anteriormente nesta seção.

    using System;
    using System.Text.RegularExpressions;
    
    public class Example
    {
        public static void Main()
        {
            string greedyPattern = @".+(\d+)\.";
            string input = "This sentence ends with the number 107325.";
            Match match;
    
            // Match from left-to-right using lazy quantifier .+?.
            match = Regex.Match(input, greedyPattern);
            if (match.Success)
                Console.WriteLine("Number at end of sentence (left-to-right): {0}",
                                  match.Groups[1].Value);
            else
                Console.WriteLine("{0} finds no match.", greedyPattern);
    
            // Match from right-to-left using greedy quantifier .+.
            match = Regex.Match(input, greedyPattern, RegexOptions.RightToLeft);
            if (match.Success)
                Console.WriteLine("Number at end of sentence (right-to-left): {0}",
                                  match.Groups[1].Value);
            else
                Console.WriteLine("{0} finds no match.", greedyPattern);
        }
    }
    // The example displays the following output:
    //       Number at end of sentence (left-to-right): 5
    //       Number at end of sentence (right-to-left): 107325
    
    Imports System.Text.RegularExpressions
    
    Module Example
        Public Sub Main()
            Dim greedyPattern As String = ".+(\d+)\."
            Dim input As String = "This sentence ends with the number 107325."
            Dim match As Match
    
            ' Match from left-to-right using lazy quantifier .+?.
            match = Regex.Match(input, greedyPattern)
            If match.Success Then
                Console.WriteLine("Number at end of sentence (left-to-right): {0}",
                                  match.Groups(1).Value)
            Else
                Console.WriteLine("{0} finds no match.", greedyPattern)
            End If
    
            ' Match from right-to-left using greedy quantifier .+.
            match = Regex.Match(input, greedyPattern, RegexOptions.RightToLeft)
            If match.Success Then
                Console.WriteLine("Number at end of sentence (right-to-left): {0}",
                                  match.Groups(1).Value)
            Else
                Console.WriteLine("{0} finds no match.", greedyPattern)
            End If
        End Sub
    End Module
    ' The example displays the following output:
    '       Number at end of sentence (left-to-right): 5
    '       Number at end of sentence (right-to-left): 107325
    

    Para obter mais informações sobre a correspondência da direita para a esquerda, consulte Opções de expressão regular.

  • Olhar positivo e negativo: (?<=subexpressão) para olhar para trás positivo e(?<! subexpressão) para olhar para trás. Esse recurso é semelhante ao lookahead, que é discutido anteriormente neste tópico. Como o mecanismo de expressão regular permite a correspondência completa da direita para a esquerda, as expressões regulares permitem olhares irrestritos. O olhar positivo e negativo também pode ser usado para evitar quantificadores de aninhamento quando a subexpressão aninhada é um superconjunto de uma expressão externa. Expressões regulares com esses quantificadores aninhados geralmente oferecem baixo desempenho. Por exemplo, o exemplo a seguir verifica se uma cadeia de caracteres começa e termina com um caractere alfanumérico e se qualquer outro caractere na cadeia de caracteres é um de um subconjunto maior. Ele forma uma parte da expressão regular usada para validar endereços de e-mail; para obter mais informações, consulte Como verificar se as cadeias de caracteres estão no formato de email válido.

    using System;
    using System.Text.RegularExpressions;
    
    public class Example
    {
        public static void Main()
        {
            string[] inputs = { "jack.sprat", "dog#", "dog#1", "me.myself",
                              "me.myself!" };
            string pattern = @"^[A-Z0-9]([-!#$%&'.*+/=?^`{}|~\w])*(?<=[A-Z0-9])$";
            foreach (string input in inputs)
            {
                if (Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase))
                    Console.WriteLine("{0}: Valid", input);
                else
                    Console.WriteLine("{0}: Invalid", input);
            }
        }
    }
    // The example displays the following output:
    //       jack.sprat: Valid
    //       dog#: Invalid
    //       dog#1: Valid
    //       me.myself: Valid
    //       me.myself!: Invalid
    
    Imports System.Text.RegularExpressions
    
    Module Example
        Public Sub Main()
            Dim inputs() As String = {"jack.sprat", "dog#", "dog#1", "me.myself",
                                       "me.myself!"}
            Dim pattern As String = "^[A-Z0-9]([-!#$%&'.*+/=?^`{}|~\w])*(?<=[A-Z0-9])$"
            For Each input As String In inputs
                If Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase) Then
                    Console.WriteLine("{0}: Valid", input)
                Else
                    Console.WriteLine("{0}: Invalid", input)
                End If
            Next
        End Sub
    End Module
    ' The example displays the following output:
    '       jack.sprat: Valid
    '       dog#: Invalid
    '       dog#1: Valid
    '       me.myself: Valid
    '       me.myself!: Invalid
    

    A expressão ^[A-Z0-9]([-!#$%&'.*+/=?^`{}|~\w])*(?<=[A-Z0-9])$ regular é definida conforme mostrado na tabela a seguir.

    Padrão Description
    ^ Comece a partida no início da string.
    [A-Z0-9] Corresponder a qualquer caractere numérico ou alfanumérico. (A comparação não diferencia maiúsculas de minúsculas.)
    ([-!#$%&'.*+/=?^`{}|~\w])* Corresponder a zero ou mais ocorrências de qualquer caractere de palavra, ou qualquer um dos seguintes caracteres: -, !, #, $, %, &, ', ., *, +, /, =, ?, ^, ', {, }, |, ou ~.
    (?<=[A-Z0-9]) Olhe para trás para o caractere anterior, que deve ser numérico ou alfanumérico. (A comparação não diferencia maiúsculas de minúsculas.)
    $ Termine a partida no final da string.

    Para obter mais informações sobre olhares positivos e negativos, consulte Agrupando construções.

Title Description
Retrocesso Fornece informações sobre como a expressão regular retrocede ramificações para encontrar correspondências alternativas.
Compilação e Reutilização Fornece informações sobre como compilar e reutilizar expressões regulares para aumentar o desempenho.
Segurança de roscas Fornece informações sobre segurança de thread de expressão regular e explica quando você deve sincronizar o acesso a objetos de expressão regular.
Expressões regulares do .NET Fornece uma visão geral do aspeto da linguagem de programação de expressões regulares.
O modelo de objeto de expressão regular Fornece informações e exemplos de código que ilustram como usar as classes de expressão regular.
Linguagem de Expressão Regular - Referência Rápida Fornece informações sobre o conjunto de caracteres, operadores e construções que você pode usar para definir expressões regulares.

Referência