Quantificadores em expressões regulares
Os quantificadores especificam quantas instâncias de um caractere, grupo ou classe de caracteres devem estar presentes na entrada para encontrar uma correspondência. A tabela a seguir lista os quantificadores com suporte no .NET:
Quantificador Greedy | Quantificador lento | Descrição |
---|---|---|
* |
*? |
Corresponde a zero ou mais vezes. |
+ |
+? |
Corresponde a uma ou mais vezes. |
? |
?? |
Corresponde a zero ou uma vez. |
{ n } |
{ n }? |
Corresponde exatamente a n vezes. |
{ n ,} |
{ n ,}? |
Corresponde a, pelo menos, n vezes. |
{ n , m } |
{ n , m }? |
Corresponde de n a m vezes. |
As quantidades n
e m
são constantes inteiras. Normalmente, os quantificadores são greedy. Eles fazem com que o mecanismo de expressões regulares corresponda a quantas ocorrências de padrões determinados forem possíveis. Acrescentar o caractere ?
a um quantificador torna-o lento. Isso faz com que o mecanismo de expressão regular corresponda ao menor número possível de ocorrências. Para obter uma descrição completa da diferença entre quantificadores greedy e lentos, confira a seção Quantificadores greedy e lentos mais adiante neste artigo.
Importante
Aninhar quantificadores, como o padrão de expressão regular (a*)*
, pode aumentar o número de comparações que o mecanismo de expressão regular precisa executar. O número de comparações pode aumentar como uma função exponencial do número de caracteres na cadeia de caracteres de entrada. Para saber mais sobre esse comportamento e suas soluções, veja Retrocesso.
Quantificadores em expressões regulares
As seções a seguir listam os quantificadores com suporte nas expressões regulares no .NET:
Observação
Se os caracteres *, +, ?, { e } forem encontrados em um padrão de expressão regular, o mecanismo de expressões regulares vai interpretá-los como quantificadores ou parte de constructos de quantificador, exceto se estiverem incluídos em uma classe de caracteres. Para interpretá-los como caracteres literais fora de uma classe de caracteres, você precisa fazer o escape, antecedendo-os com uma barra invertida. Por exemplo, a cadeia de caracteres \*
em um padrão de expressão regular é interpretada como um caractere asterisco (“*”) integral.
Corresponder a zero ou mais vezes: *
O quantificador *
corresponde ao elemento anterior zero ou mais vezes. É equivalente ao quantificador {0,}
. *
é um quantificador Greedy, cujo equivalente lento é *?
.
O exemplo a seguir ilustra essa expressão regular. Cinco dos grupos de nove dígitos na cadeia de caracteres de entrada correspondem ao padrão e quatro (95
, 929
, 9219
e 9919
) não.
string pattern = @"\b91*9*\b";
string input = "99 95 919 929 9119 9219 999 9919 91119";
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:
// '99' found at position 0.
// '919' found at position 6.
// '9119' found at position 14.
// '999' found at position 24.
// '91119' found at position 33.
Dim pattern As String = "\b91*9*\b"
Dim input As String = "99 95 919 929 9119 9219 999 9919 91119"
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index)
Next
' The example displays the following output:
' '99' found at position 0.
' '919' found at position 6.
' '9119' found at position 14.
' '999' found at position 24.
' '91119' found at position 33.
O padrão de expressão regular é definido conforme mostrado na tabela a seguir:
Padrão | Descrição |
---|---|
\b |
Especifica que a correspondência deve começar em um limite de palavra. |
91* |
Corresponde a uma classe 9 seguida por zero ou mais 1 caracteres. |
9* |
Corresponde a zero ou mais caracteres 9 . |
\b |
Especifica que a correspondência deve terminar em um limite de palavra. |
Corresponder a um ou mais vezes: +
O quantificador +
corresponde ao elemento anterior uma ou mais vezes. É equivalente a {1,}
. +
é um quantificador Greedy, cujo equivalente lento é +?
.
Por exemplo, a expressão regular \ban+\w*?\b
tenta corresponder a palavras inteiras que começam com a letra a
seguidas por uma ou mais instâncias da letra n
. O exemplo a seguir ilustra essa expressão regular. A expressão regular corresponde às palavras an
, annual
, announcement
e antique
, e não correspondem corretamente a autumn
e all
.
string pattern = @"\ban+\w*?\b";
string input = "Autumn is a great time for an annual announcement to all antique collectors.";
foreach (Match match in Regex.Matches(input, pattern, RegexOptions.IgnoreCase))
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index);
// The example displays the following output:
// 'an' found at position 27.
// 'annual' found at position 30.
// 'announcement' found at position 37.
// 'antique' found at position 57.
Dim pattern As String = "\ban+\w*?\b"
Dim input As String = "Autumn is a great time for an annual announcement to all antique collectors."
For Each match As Match In Regex.Matches(input, pattern, RegexOptions.IgnoreCase)
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index)
Next
' The example displays the following output:
' 'an' found at position 27.
' 'annual' found at position 30.
' 'announcement' found at position 37.
' 'antique' found at position 57.
O padrão de expressão regular é definido conforme mostrado na tabela a seguir:
Padrão | Descrição |
---|---|
\b |
Iniciar em um limite de palavra. |
an+ |
Corresponde a um a seguido por um ou mais caracteres n . |
\w*? |
Corresponde a um caractere de palavra zero ou mais vezes, mas o menor número de vezes possível. |
\b |
Terminar em um limite de palavra. |
Corresponder a zero ou uma vez: ?
O quantificador ?
corresponde ao elemento anterior zero ou uma vez. É equivalente a {0,1}
. ?
é um quantificador Greedy, cujo equivalente lento é ??
.
Por exemplo, a expressão regular \ban?\b
tenta corresponder a palavras inteiras que começam com a letra a
seguidas por zero ou uma instância da letra n
. Em outras palavras, ele tenta corresponder às palavras a
e an
. O exemplo a seguir ilustra essa expressão regular:
string pattern = @"\ban?\b";
string input = "An amiable animal with a large snout and an animated nose.";
foreach (Match match in Regex.Matches(input, pattern, RegexOptions.IgnoreCase))
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index);
// The example displays the following output:
// 'An' found at position 0.
// 'a' found at position 23.
// 'an' found at position 42.
Dim pattern As String = "\ban?\b"
Dim input As String = "An amiable animal with a large snout and an animated nose."
For Each match As Match In Regex.Matches(input, pattern, RegexOptions.IgnoreCase)
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index)
Next
' The example displays the following output:
' 'An' found at position 0.
' 'a' found at position 23.
' 'an' found at position 42.
O padrão de expressão regular é definido conforme mostrado na tabela a seguir:
Padrão | Descrição |
---|---|
\b |
Iniciar em um limite de palavra. |
an? |
Corresponde a um a seguido por zero ou um caractere n . |
\b |
Terminar em um limite de palavra. |
Corresponder exatamente a n vezes: {n}
O quantificador {
n}
corresponde ao elemento anterior exatamente n vezes, em que n é qualquer inteiro. {
n}
é um quantificador Greedy cujo equivalente lento é {
n}?
.
Por exemplo, a expressão regular \b\d+\,\d{3}\b
tenta corresponder a um limite de palavra seguido por um ou mais dígitos decimais seguidos por três dígitos decimais seguidos por um limite de palavra. O exemplo a seguir ilustra essa expressão regular:
string pattern = @"\b\d+\,\d{3}\b";
string input = "Sales totaled 103,524 million in January, " +
"106,971 million in February, but only " +
"943 million in March.";
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:
// '103,524' found at position 14.
// '106,971' found at position 45.
Dim pattern As String = "\b\d+\,\d{3}\b"
Dim input As String = "Sales totaled 103,524 million in January, " + _
"106,971 million in February, but only " + _
"943 million in March."
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index)
Next
' The example displays the following output:
' '103,524' found at position 14.
' '106,971' found at position 45.
O padrão de expressão regular é definido conforme mostrado na tabela a seguir:
Padrão | Descrição |
---|---|
\b |
Iniciar em um limite de palavra. |
\d+ |
Corresponde a um ou mais dígitos decimais. |
\, |
Corresponde a um caractere de vírgula. |
\d{3} |
Corresponde a três dígitos decimais. |
\b |
Terminar em um limite de palavra. |
Corresponder a pelo menos n vezes: {n,}
O quantificador {
n,}
corresponde ao elemento anterior pelo menos n vezes, em que n é qualquer inteiro. {
n,}
é um quantificador Greedy cujo equivalente lento é {
n,}?
.
Por exemplo, a expressão regular \b\d{2,}\b\D+
tenta corresponder a um limite de palavra seguido por pelo menos dois dígitos seguidos por um limite de palavra e um caractere não dígito. O exemplo a seguir ilustra essa expressão regular. A expressão regular não corresponde à frase "7 days"
porque contém apenas um dígito decimal, mas corresponde com êxito às frases "10 weeks"
e "300 years"
.
string pattern = @"\b\d{2,}\b\D+";
string input = "7 days, 10 weeks, 300 years";
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:
// '10 weeks, ' found at position 8.
// '300 years' found at position 18.
Dim pattern As String = "\b\d{2,}\b\D+"
Dim input As String = "7 days, 10 weeks, 300 years"
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index)
Next
' The example displays the following output:
' '10 weeks, ' found at position 8.
' '300 years' found at position 18.
O padrão de expressão regular é definido conforme mostrado na tabela a seguir:
Padrão | Descrição |
---|---|
\b |
Iniciar em um limite de palavra. |
\d{2,} |
Corresponde a pelo menos dois dígitos decimais. |
\b |
Corresponde a um limite de palavra. |
\D+ |
Corresponde a pelo menos uma casa não decimal. |
Corresponder entre n e m vezes: {n,m}
O quantificador {
n,
m}
corresponde ao elemento anterior pelo menos n vezes, mas não mais de m vezes, em que n e m são inteiros. {
n,
m}
é um quantificador Greedy cujo equivalente lento é {
n,
m}?
.
No exemplo a seguir, a expressão regular (00\s){2,4}
tenta corresponder a entre duas e quatro ocorrências de dois dígitos zero seguidos por um espaço. A parte final da cadeia de caracteres de entrada inclui esse padrão de cinco vezes em vez de no máximo quatro. No entanto, apenas a parte inicial dessa subcadeia de caracteres (até o espaço e o quinto par de zeros) corresponde ao padrão de expressão regular.
string pattern = @"(00\s){2,4}";
string input = "0x00 FF 00 00 18 17 FF 00 00 00 21 00 00 00 00 00";
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:
// '00 00 ' found at position 8.
// '00 00 00 ' found at position 23.
// '00 00 00 00 ' found at position 35.
Dim pattern As String = "(00\s){2,4}"
Dim input As String = "0x00 FF 00 00 18 17 FF 00 00 00 21 00 00 00 00 00"
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index)
Next
' The example displays the following output:
' '00 00 ' found at position 8.
' '00 00 00 ' found at position 23.
' '00 00 00 00 ' found at position 35.
Corresponder a zero ou mais vezes (correspondência lenta): *?
O quantificador *?
corresponde ao elemento anterior zero ou mais vezes, mas o menor número de vezes possível. É a contraparte lenta do quantificador greedy *
.
No exemplo a seguir, a expressão regular \b\w*?oo\w*?\b
corresponde a todas as palavras que contêm a cadeia de caracteres oo
.
string pattern = @"\b\w*?oo\w*?\b";
string input = "woof root root rob oof woo woe";
foreach (Match match in Regex.Matches(input, pattern, RegexOptions.IgnoreCase))
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index);
// The example displays the following output:
// 'woof' found at position 0.
// 'root' found at position 5.
// 'root' found at position 10.
// 'oof' found at position 19.
// 'woo' found at position 23.
Dim pattern As String = "\b\w*?oo\w*?\b"
Dim input As String = "woof root root rob oof woo woe"
For Each match As Match In Regex.Matches(input, pattern, RegexOptions.IgnoreCase)
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index)
Next
' The example displays the following output:
' 'woof' found at position 0.
' 'root' found at position 5.
' 'root' found at position 10.
' 'oof' found at position 19.
' 'woo' found at position 23.
O padrão de expressão regular é definido conforme mostrado na tabela a seguir:
Padrão | Descrição |
---|---|
\b |
Iniciar em um limite de palavra. |
\w*? |
Corresponde a zero ou mais caracteres de palavra, mas o menor número de caracteres possível. |
oo |
Corresponde à cadeia de caracteres oo . |
\w*? |
Corresponde a zero ou mais caracteres de palavra, mas o menor número de caracteres possível. |
\b |
Terminar em um limite de palavra. |
Corresponder a uma ou mais vezes (correspondência lenta): +?
O quantificador +?
corresponde ao elemento anterior uma ou mais vezes, mas o menor número de vezes possível. É a contraparte lenta do quantificador greedy +
.
Por exemplo, a expressão regular \b\w+?\b
corresponde a um ou mais caracteres separados por limites de palavra. O exemplo a seguir ilustra essa expressão regular:
string pattern = @"\b\w+?\b";
string input = "Aa Bb Cc Dd Ee Ff";
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:
// 'Aa' found at position 0.
// 'Bb' found at position 3.
// 'Cc' found at position 6.
// 'Dd' found at position 9.
// 'Ee' found at position 12.
// 'Ff' found at position 15.
Dim pattern As String = "\b\w+?\b"
Dim input As String = "Aa Bb Cc Dd Ee Ff"
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index)
Next
' The example displays the following output:
' 'Aa' found at position 0.
' 'Bb' found at position 3.
' 'Cc' found at position 6.
' 'Dd' found at position 9.
' 'Ee' found at position 12.
' 'Ff' found at position 15.
Corresponder a zero ou uma vez (correspondência lenta): ??
O quantificador ??
corresponde ao elemento anterior zero ou uma vez, mas o menor número de vezes possível. É a contraparte lenta do quantificador greedy ?
.
Por exemplo, a expressão regular ^\s*(System.)??Console.Write(Line)??\(??
tenta corresponder às cadeias de caracteres Console.Write
ou Console.WriteLine
. A cadeia de caracteres também pode incluir System.
antes de Console
, e pode ser seguida por um parêntese de abertura. A cadeia de caracteres deve estar no início de uma linha, embora possa ser antecedida por espaço em branco. O exemplo a seguir ilustra essa expressão regular:
string pattern = @"^\s*(System.)??Console.Write(Line)??\(??";
string input = "System.Console.WriteLine(\"Hello!\")\n" +
"Console.Write(\"Hello!\")\n" +
"Console.WriteLine(\"Hello!\")\n" +
"Console.ReadLine()\n" +
" Console.WriteLine";
foreach (Match match in Regex.Matches(input, pattern,
RegexOptions.IgnorePatternWhitespace |
RegexOptions.IgnoreCase |
RegexOptions.Multiline))
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index);
// The example displays the following output:
// 'System.Console.Write' found at position 0.
// 'Console.Write' found at position 36.
// 'Console.Write' found at position 61.
// ' Console.Write' found at position 110.
Dim pattern As String = "^\s*(System.)??Console.Write(Line)??\(??"
Dim input As String = "System.Console.WriteLine(""Hello!"")" + vbCrLf + _
"Console.Write(""Hello!"")" + vbCrLf + _
"Console.WriteLine(""Hello!"")" + vbCrLf + _
"Console.ReadLine()" + vbCrLf + _
" Console.WriteLine"
For Each match As Match In Regex.Matches(input, pattern, _
RegexOptions.IgnorePatternWhitespace Or RegexOptions.IgnoreCase Or RegexOptions.MultiLine)
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index)
Next
' The example displays the following output:
' 'System.Console.Write' found at position 0.
' 'Console.Write' found at position 36.
' 'Console.Write' found at position 61.
' ' Console.Write' found at position 110.
O padrão de expressão regular é definido conforme mostrado na tabela a seguir:
Padrão | Descrição |
---|---|
^ |
Corresponde ao início do fluxo de entrada. |
\s* |
Corresponde a zero ou mais caracteres de espaço em branco. |
(System.)?? |
Corresponde a zero ou uma ocorrência da cadeia de caracteres System. . |
Console.Write |
Corresponde à cadeia de caracteres Console.Write . |
(Line)?? |
Corresponde a zero ou uma ocorrência da cadeia de caracteres Line . |
\(?? |
Corresponde a zero ou uma ocorrência do parêntese de abertura. |
Corresponder exatamente a n vezes (correspondência lenta): {n}?
O quantificador {
n}?
corresponde ao elemento anterior exatamente n
vezes, em que n é qualquer inteiro. É a contraparte lenta do quantificador greedy {
n}
.
No exemplo a seguir, a expressão regular \b(\w{3,}?\.){2}?\w{3,}?\b
é usada para identificar um endereço web. A expressão corresponde a www.microsoft.com
e msdn.microsoft.com
, mas não corresponde a mywebsite
ou mycompany.com
.
string pattern = @"\b(\w{3,}?\.){2}?\w{3,}?\b";
string input = "www.microsoft.com msdn.microsoft.com mywebsite mycompany.com";
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:
// 'www.microsoft.com' found at position 0.
// 'msdn.microsoft.com' found at position 18.
Dim pattern As String = "\b(\w{3,}?\.){2}?\w{3,}?\b"
Dim input As String = "www.microsoft.com msdn.microsoft.com mywebsite mycompany.com"
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index)
Next
' The example displays the following output:
' 'www.microsoft.com' found at position 0.
' 'msdn.microsoft.com' found at position 18.
O padrão de expressão regular é definido conforme mostrado na tabela a seguir:
Padrão | Descrição |
---|---|
\b |
Iniciar em um limite de palavra. |
(\w{3,}?\.) |
Corresponde a pelo menos três caracteres de palavra, mas o menor número de caracteres possível, seguido por um caractere de ponto. Esse padrão é o primeiro grupo de captura. |
(\w{3,}?\.){2}? |
Corresponde ao padrão no primeiro grupo duas vezes, mas o menor número de vezes possível. |
\b |
Termina a correspondência em um limite de palavra. |
Corresponder a pelo menos n vezes (correspondência lenta): {n,}?
O quantificador {
n,}?
corresponde ao elemento anterior pelo menos n
vezes, em que n é qualquer inteiro, mas o menor número de vezes possível. É o equivalente lento do quantificador greedy {
n,}
.
Veja o exemplo do quantificador {
n}?
na seção anterior para obter uma ilustração. A expressão regular nesse exemplo usa o quantificador {
n,}
para corresponder a uma cadeia de caracteres que tem, pelo menos, três caracteres seguidos por um ponto final.
Corresponder entre n e m vezes (correspondência lenta): {n,m}?
O quantificador {
n,
m}?
corresponde ao elemento anterior entre n
e m
vezes, em que n e m são inteiros, mas o menor número de vezes possível. É o equivalente lento do quantificador greedy {
n,
m}
.
No exemplo a seguir, a expressão regular \b[A-Z](\w*?\s*?){1,10}[.!?]
corresponde a frases que contêm entre uma e dez palavras. Corresponde a todas as frases na cadeia de caracteres de entrada, exceto por uma frase que contém 18 palavras.
string pattern = @"\b[A-Z](\w*?\s*?){1,10}[.!?]";
string input = "Hi. I am writing a short note. Its purpose is " +
"to test a regular expression that attempts to find " +
"sentences with ten or fewer words. Most sentences " +
"in this note are short.";
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:
// 'Hi.' found at position 0.
// 'I am writing a short note.' found at position 4.
// 'Most sentences in this note are short.' found at position 132.
Dim pattern As String = "\b[A-Z](\w*\s?){1,10}?[.!?]"
Dim input As String = "Hi. I am writing a short note. Its purpose is " + _
"to test a regular expression that attempts to find " + _
"sentences with ten or fewer words. Most sentences " + _
"in this note are short."
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine("'{0}' found at position {1}.", match.Value, match.Index)
Next
' The example displays the following output:
' 'Hi.' found at position 0.
' 'I am writing a short note.' found at position 4.
' 'Most sentences in this note are short.' found at position 132.
O padrão de expressão regular é definido conforme mostrado na tabela a seguir:
Padrão | Descrição |
---|---|
\b |
Iniciar em um limite de palavra. |
[A-Z] |
Corresponde a um caractere maiúscula de A a Z. |
(\w*?\s*?) |
Corresponde a zero ou mais caracteres de palavra, seguidos por um ou mais caracteres de espaço em branco, mas o menor número de vezes possível. Esse padrão é o primeiro grupo de captura. |
{1,10} |
Corresponde ao padrão anterior entre 1 e 10 vezes. |
[.!?] |
Corresponde a qualquer um dos caracteres de pontuação . , ! ou ? . |
Quantificadores Greedy e lentos
Alguns quantificadores têm duas versões:
Uma versão Greedy.
Um quantificador Greedy tenta corresponder a um elemento tantas vezes quanto possível.
Uma versão não Greedy (ou lenta).
Um quantificador não Greedy tenta corresponder a um elemento o menor número de vezes possível. Você pode transformar um quantificador greedy em um quantificador lento adicionando um
?
.
Considere uma expressão regular que se destina a extrair os últimos quatro dígitos de uma cadeia de caracteres de números, como um número de cartão de crédito. A versão da expressão regular que usa o quantificador Greedy *
é \b.*([0-9]{4})\b
. No entanto, se uma cadeia de caracteres contiver dois números, essa expressão regular corresponde aos últimos quatro dígitos do segundo número, como mostra o exemplo a seguir:
string greedyPattern = @"\b.*([0-9]{4})\b";
string input1 = "1112223333 3992991999";
foreach (Match match in Regex.Matches(input1, greedyPattern))
Console.WriteLine("Account ending in ******{0}.", match.Groups[1].Value);
// The example displays the following output:
// Account ending in ******1999.
Dim greedyPattern As String = "\b.*([0-9]{4})\b"
Dim input1 As String = "1112223333 3992991999"
For Each match As Match In Regex.Matches(input1, greedypattern)
Console.WriteLine("Account ending in ******{0}.", match.Groups(1).Value)
Next
' The example displays the following output:
' Account ending in ******1999.
A expressão regular não corresponde ao primeiro número porque o quantificador *
tenta corresponder ao elemento anterior tantas vezes quanto possível em toda a cadeia de caracteres e encontra sua correspondência no final da cadeia de caracteres.
Esse comportamento não é o desejado. Em vez disso, é possível usar o quantificador lento *?
para extrair dígitos de ambos os números, como mostra o exemplo a seguir:
string lazyPattern = @"\b.*?([0-9]{4})\b";
string input2 = "1112223333 3992991999";
foreach (Match match in Regex.Matches(input2, lazyPattern))
Console.WriteLine("Account ending in ******{0}.", match.Groups[1].Value);
// The example displays the following output:
// Account ending in ******3333.
// Account ending in ******1999.
Dim lazyPattern As String = "\b.*?([0-9]{4})\b"
Dim input2 As String = "1112223333 3992991999"
For Each match As Match In Regex.Matches(input2, lazypattern)
Console.WriteLine("Account ending in ******{0}.", match.Groups(1).Value)
Next
' The example displays the following output:
' Account ending in ******3333.
' Account ending in ******1999.
Na maioria dos casos, expressões regulares com quantificadores Greedy e lentos retornam as mesmas correspondências. Geralmente retornam resultados diferentes quando são usadas com o metacaractere curinga (.
), que corresponde a qualquer caractere.
Quantificadores e correspondências vazias
Os quantificadores *
, +
e {
n,
m}
e seus equivalentes lentos nunca se repetem depois de uma correspondência vazia quando o número mínimo de capturas foi encontrado. Essa regra impede que quantificadores entrem em loops infinitos em correspondências vazias de subexpressão quando o número máximo de capturas de grupo possíveis é infinito ou quase infinito.
Por exemplo, o código a seguir mostra o resultado de uma chamada para o método Regex.Match com o padrão de expressão regular (a?)*
que corresponde a zero ou a um caractere a
zero ou mais vezes. Observe que o grupo de captura único captura cada a
bem como String.Empty, mas que não há uma segunda correspondência vazia, porque a primeira correspondência vazia faz com que o quantificador pare de se repetir.
using System;
using System.Text.RegularExpressions;
public class Example
{
public static void Main()
{
string pattern = "(a?)*";
string input = "aaabbb";
Match match = Regex.Match(input, pattern);
Console.WriteLine("Match: '{0}' at index {1}",
match.Value, match.Index);
if (match.Groups.Count > 1) {
GroupCollection groups = match.Groups;
for (int grpCtr = 1; grpCtr <= groups.Count - 1; grpCtr++) {
Console.WriteLine(" Group {0}: '{1}' at index {2}",
grpCtr,
groups[grpCtr].Value,
groups[grpCtr].Index);
int captureCtr = 0;
foreach (Capture capture in groups[grpCtr].Captures) {
captureCtr++;
Console.WriteLine(" Capture {0}: '{1}' at index {2}",
captureCtr, capture.Value, capture.Index);
}
}
}
}
}
// The example displays the following output:
// Match: 'aaa' at index 0
// Group 1: '' at index 3
// Capture 1: 'a' at index 0
// Capture 2: 'a' at index 1
// Capture 3: 'a' at index 2
// Capture 4: '' at index 3
Imports System.Text.RegularExpressions
Module Example
Public Sub Main()
Dim pattern As String = "(a?)*"
Dim input As String = "aaabbb"
Dim match As Match = Regex.Match(input, pattern)
Console.WriteLine("Match: '{0}' at index {1}",
match.Value, match.Index)
If match.Groups.Count > 1 Then
Dim groups As GroupCollection = match.Groups
For grpCtr As Integer = 1 To groups.Count - 1
Console.WriteLine(" Group {0}: '{1}' at index {2}",
grpCtr,
groups(grpCtr).Value,
groups(grpCtr).Index)
Dim captureCtr As Integer = 0
For Each capture As Capture In groups(grpCtr).Captures
captureCtr += 1
Console.WriteLine(" Capture {0}: '{1}' at index {2}",
captureCtr, capture.Value, capture.Index)
Next
Next
End If
End Sub
End Module
' The example displays the following output:
' Match: 'aaa' at index 0
' Group 1: '' at index 3
' Capture 1: 'a' at index 0
' Capture 2: 'a' at index 1
' Capture 3: 'a' at index 2
' Capture 4: '' at index 3
Para ver a diferença prática entre um grupo de captura que define um número mínimo e máximo de captura e um que define um número fixo de capturas, considere os padrões de expressão regular (a\1|(?(1)\1)){0,2}
e (a\1|(?(1)\1)){2}
. Ambas as expressões regulares consistem em um único grupo de captura, que é definido na tabela a seguir:
Padrão | Descrição |
---|---|
(a\1 |
Faça qualquer correspondência a a juntamente com o valor do primeiro grupo de captura … |
|(?(1) |
… ou teste se o primeiro grupo de captura foi definido. O constructo (?(1) não define um grupo de captura. |
\1)) |
Se o primeiro grupo capturado existir, faça uma correspondência ao valor. Se o grupo não existir, será correspondente a String.Empty. |
A primeira expressão regular tenta corresponder a esse padrão entre zero e duas vezes; a segunda, exatamente duas vezes. Como o primeiro padrão atinge seu número mínimo de capturas com sua primeira captura de String.Empty, ele nunca se repete para tentar corresponder a a\1
. O quantificador {0,2}
permite apenas correspondências vazias na última iteração. Por outro lado, a segunda expressão regular corresponde a a
porque avalia a\1
uma segunda vez. O número mínimo de iterações, 2, força o mecanismo a repetir após uma correspondência vazia.
using System;
using System.Text.RegularExpressions;
public class Example
{
public static void Main()
{
string pattern, input;
pattern = @"(a\1|(?(1)\1)){0,2}";
input = "aaabbb";
Console.WriteLine("Regex pattern: {0}", pattern);
Match match = Regex.Match(input, pattern);
Console.WriteLine("Match: '{0}' at position {1}.",
match.Value, match.Index);
if (match.Groups.Count > 1) {
for (int groupCtr = 1; groupCtr <= match.Groups.Count - 1; groupCtr++)
{
Group group = match.Groups[groupCtr];
Console.WriteLine(" Group: {0}: '{1}' at position {2}.",
groupCtr, group.Value, group.Index);
int captureCtr = 0;
foreach (Capture capture in group.Captures) {
captureCtr++;
Console.WriteLine(" Capture: {0}: '{1}' at position {2}.",
captureCtr, capture.Value, capture.Index);
}
}
}
Console.WriteLine();
pattern = @"(a\1|(?(1)\1)){2}";
Console.WriteLine("Regex pattern: {0}", pattern);
match = Regex.Match(input, pattern);
Console.WriteLine("Matched '{0}' at position {1}.",
match.Value, match.Index);
if (match.Groups.Count > 1) {
for (int groupCtr = 1; groupCtr <= match.Groups.Count - 1; groupCtr++)
{
Group group = match.Groups[groupCtr];
Console.WriteLine(" Group: {0}: '{1}' at position {2}.",
groupCtr, group.Value, group.Index);
int captureCtr = 0;
foreach (Capture capture in group.Captures) {
captureCtr++;
Console.WriteLine(" Capture: {0}: '{1}' at position {2}.",
captureCtr, capture.Value, capture.Index);
}
}
}
}
}
// The example displays the following output:
// Regex pattern: (a\1|(?(1)\1)){0,2}
// Match: '' at position 0.
// Group: 1: '' at position 0.
// Capture: 1: '' at position 0.
//
// Regex pattern: (a\1|(?(1)\1)){2}
// Matched 'a' at position 0.
// Group: 1: 'a' at position 0.
// Capture: 1: '' at position 0.
// Capture: 2: 'a' at position 0.
Imports System.Text.RegularExpressions
Module Example
Public Sub Main()
Dim pattern, input As String
pattern = "(a\1|(?(1)\1)){0,2}"
input = "aaabbb"
Console.WriteLine("Regex pattern: {0}", pattern)
Dim match As Match = Regex.Match(input, pattern)
Console.WriteLine("Match: '{0}' at position {1}.",
match.Value, match.Index)
If match.Groups.Count > 1 Then
For groupCtr As Integer = 1 To match.Groups.Count - 1
Dim group As Group = match.Groups(groupCtr)
Console.WriteLine(" Group: {0}: '{1}' at position {2}.",
groupCtr, group.Value, group.Index)
Dim captureCtr As Integer = 0
For Each capture As Capture In group.Captures
captureCtr += 1
Console.WriteLine(" Capture: {0}: '{1}' at position {2}.",
captureCtr, capture.Value, capture.Index)
Next
Next
End If
Console.WriteLine()
pattern = "(a\1|(?(1)\1)){2}"
Console.WriteLine("Regex pattern: {0}", pattern)
match = Regex.Match(input, pattern)
Console.WriteLine("Matched '{0}' at position {1}.",
match.Value, match.Index)
If match.Groups.Count > 1 Then
For groupCtr As Integer = 1 To match.Groups.Count - 1
Dim group As Group = match.Groups(groupCtr)
Console.WriteLine(" Group: {0}: '{1}' at position {2}.",
groupCtr, group.Value, group.Index)
Dim captureCtr As Integer = 0
For Each capture As Capture In group.Captures
captureCtr += 1
Console.WriteLine(" Capture: {0}: '{1}' at position {2}.",
captureCtr, capture.Value, capture.Index)
Next
Next
End If
End Sub
End Module
' The example displays the following output:
' Regex pattern: (a\1|(?(1)\1)){0,2}
' Match: '' at position 0.
' Group: 1: '' at position 0.
' Capture: 1: '' at position 0.
'
' Regex pattern: (a\1|(?(1)\1)){2}
' Matched 'a' at position 0.
' Group: 1: 'a' at position 0.
' Capture: 1: '' at position 0.
' Capture: 2: 'a' at position 0.