Konstrukce zpětných odkazů v regulárních výrazech
Zpětné odvozování představují pohodlný způsob identifikace opakovaného znaku nebo podřetězce v řetězci. Pokud například vstupní řetězec obsahuje více výskytů libovolného podřetězce, můžete se shodovat s prvním výskytem se skupinou zachycení a pak pomocí zpětného odvozování spárovat následné výskyty podřetězce.
Poznámka:
Samostatná syntaxe se používá k odkazování na pojmenované a číslované zachycené skupiny v náhradních řetězcích. Další informace naleznete v tématu Nahrazení.
.NET definuje samostatné jazykové prvky, které odkazují na číslovaný a pojmenovaný záznam skupin. Další informace o zachytávání skupin naleznete v tématu Seskupování konstruktorů.
Číslovaný backreference
Číslovaný backreference používá následující syntaxi:
\
číslo
where number is the ordinal position of the capturing group in the regular expression. \4
Například odpovídá obsahu čtvrté skupiny zachycení. Pokud číslo není definováno ve vzoru regulárního výrazu, dojde k chybě analýzy a modul regulárních výrazů vyvolá chybu ArgumentException. Například regulární výraz \b(\w+)\s\1
je platný, protože (\w+)
je první a pouze zachytává skupinu ve výrazu. Na druhou stranu je \b(\w+)\s\2
neplatná a vyvolá výjimku argumentu, protože neexistuje žádné zachytávání skupin číslování \2
. Kromě toho, pokud číslo identifikuje zachytávání skupiny v určité pořadové pozici, ale tato zachytávání skupiny byla přiřazena číselný název jiný než jeho pořadová pozice, analyzátor regulárních výrazů ArgumentExceptiontaké vyvolá .
Všimněte si nejednoznačnosti mezi osmičkovými řídicími kódy (například \16
) a \
zpětnými odvozováním čísel , které používají stejnou notaci. Tato nejednoznačnost se vyřeší následujícím způsobem:
Výrazy
\1
se\9
vždy interpretují jako zpětné odvozování a ne jako osmičkové kódy.Pokud je první číslice výrazu multidigit 8 nebo 9 (například
\80
nebo\91
), výraz interpretovaný jako literál.Výrazy z
\10
a vyšší se považují za zpětné odvozování, pokud je k číslu odpovídající zpětné odvozování. V opačném případě se interpretují jako osmičkové kódy.Pokud regulární výraz obsahuje zpětné odvozování na nedefinované číslo skupiny, dojde k chybě analýzy a modul regulárních výrazů ArgumentExceptionvyvolá chybu .
Pokud je nejednoznačnost problémem, můžete použít \k<
notaci názvu>
, která je jednoznačná a nelze ji zaměňovat s osmičkovými kódy znaků. Podobně šestnáctkové kódy, jako \xdd
jsou jednoznačné, a nelze je zaměňovat s backreferencemi.
Následující příklad najde v řetězci dvojité znaky slova. Definuje regulární výraz, (\w)\1
který se skládá z následujících prvků.
Element (Prvek) | Popis |
---|---|
(\w) |
Porovná znak slova a přiřadí ho první zachycené skupině. |
\1 |
Porovná další znak, který je stejný jako hodnota první zachycené skupiny. |
using System;
using System.Text.RegularExpressions;
public class Example
{
public static void Main()
{
string pattern = @"(\w)\1";
string input = "trellis llama webbing dresser swagger";
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine("Found '{0}' at position {1}.",
match.Value, match.Index);
}
}
// The example displays the following output:
// Found 'll' at position 3.
// Found 'll' at position 8.
// Found 'bb' at position 16.
// Found 'ss' at position 25.
// Found 'gg' at position 33.
Imports System.Text.RegularExpressions
Module Example
Public Sub Main()
Dim pattern As String = "(\w)\1"
Dim input As String = "trellis llama webbing dresser swagger"
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine("Found '{0}' at position {1}.", _
match.Value, match.Index)
Next
End Sub
End Module
' The example displays the following output:
' Found 'll' at position 3.
' Found 'll' at position 8.
' Found 'bb' at position 16.
' Found 'ss' at position 25.
' Found 'gg' at position 33.
Pojmenované zpětné odvozy
Pojmenovaná backreference je definována pomocí následující syntaxe:
\k<
Jméno >
nebo:
\k'
Jméno '
where name is the name of a capturing group defined in the regular expression pattern. Pokud název není definován v vzoru regulárního výrazu, dojde k chybě analýzy a modul regulárních výrazů ArgumentExceptionvyvolá chybu .
Následující příklad najde v řetězci dvojité znaky slova. Definuje regulární výraz, (?<char>\w)\k<char>
který se skládá z následujících prvků.
Element (Prvek) | Popis |
---|---|
(?<char>\w) |
Porovná znak slova a přiřadí ho k zachycené skupině s názvem char . |
\k<char> |
Porovná další znak, který je stejný jako hodnota zachycené char skupiny. |
using System;
using System.Text.RegularExpressions;
public class Example
{
public static void Main()
{
string pattern = @"(?<char>\w)\k<char>";
string input = "trellis llama webbing dresser swagger";
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine("Found '{0}' at position {1}.",
match.Value, match.Index);
}
}
// The example displays the following output:
// Found 'll' at position 3.
// Found 'll' at position 8.
// Found 'bb' at position 16.
// Found 'ss' at position 25.
// Found 'gg' at position 33.
Imports System.Text.RegularExpressions
Module Example
Public Sub Main()
Dim pattern As String = "(?<char>\w)\k<char>"
Dim input As String = "trellis llama webbing dresser swagger"
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine("Found '{0}' at position {1}.", _
match.Value, match.Index)
Next
End Sub
End Module
' The example displays the following output:
' Found 'll' at position 3.
' Found 'll' at position 8.
' Found 'bb' at position 16.
' Found 'ss' at position 25.
' Found 'gg' at position 33.
Pojmenované číselné backreference
V pojmenovaném zpětném odvozování s \k
názvem může být také řetězcová reprezentace čísla. Například následující příklad používá regulární výraz (?<2>\w)\k<2>
k vyhledání dvouslovných znaků v řetězci. V tomto případě příklad definuje zachytávání skupiny, která má explicitně název "2", a backreference má odpovídající název "2".
using System;
using System.Text.RegularExpressions;
public class Example
{
public static void Main()
{
string pattern = @"(?<2>\w)\k<2>";
string input = "trellis llama webbing dresser swagger";
foreach (Match match in Regex.Matches(input, pattern))
Console.WriteLine("Found '{0}' at position {1}.",
match.Value, match.Index);
}
}
// The example displays the following output:
// Found 'll' at position 3.
// Found 'll' at position 8.
// Found 'bb' at position 16.
// Found 'ss' at position 25.
// Found 'gg' at position 33.
Imports System.Text.RegularExpressions
Module Example
Public Sub Main()
Dim pattern As String = "(?<2>\w)\k<2>"
Dim input As String = "trellis llama webbing dresser swagger"
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine("Found '{0}' at position {1}.", _
match.Value, match.Index)
Next
End Sub
End Module
' The example displays the following output:
' Found 'll' at position 3.
' Found 'll' at position 8.
' Found 'bb' at position 16.
' Found 'ss' at position 25.
' Found 'gg' at position 33.
Pokud je název řetězcovou reprezentací čísla a žádná zachycená skupina nemá tento název,\k<
název>
je stejný jako číslo zpětného odvozování\
, kde číslo je pořadová pozice zachycení. V následujícím příkladu existuje jedna zachycená skupina s názvem char
. Konstruktor backreference odkazuje na něj jako \k<1>
. Jak ukazuje výstup z příkladu, volání úspěšné Regex.IsMatch , protože char
je první zachytácí skupina.
using System;
using System.Text.RegularExpressions;
public class Example
{
public static void Main()
{
Console.WriteLine(Regex.IsMatch("aa", @"(?<char>\w)\k<1>"));
// Displays "True".
}
}
Imports System.Text.RegularExpressions
Module Example
Public Sub Main()
Console.WriteLine(Regex.IsMatch("aa", "(?<char>\w)\k<1>"))
' Displays "True".
End Sub
End Module
Pokud je však název řetězcovou reprezentací čísla a zachytávací skupina v této pozici byla explicitně přiřazena číselný název, analyzátor regulárních výrazů nemůže identifikovat zachytávací skupinu podle jeho pořadové pozice. Místo toho vyvolá .ArgumentException Jediná skupina zachycení v následujícím příkladu má název "2". Vzhledem k tomu, že se \k
konstruktor používá k definování zpětného odvozování s názvem "1", parser regulárních výrazů nemůže identifikovat první zachytávací skupinu a vyvolá výjimku.
using System;
using System.Text.RegularExpressions;
public class Example
{
public static void Main()
{
Console.WriteLine(Regex.IsMatch("aa", @"(?<2>\w)\k<1>"));
// Throws an ArgumentException.
}
}
Imports System.Text.RegularExpressions
Module Example
Public Sub Main()
Console.WriteLine(Regex.IsMatch("aa", "(?<2>\w)\k<1>"))
' Throws an ArgumentException.
End Sub
End Module
Co se shoduje s backreferencemi
Zpětné odvozování odkazuje na nejnovější definici skupiny (při porovnávání zleva nejvíce vlevo). Když skupina provede více zachycení, zpětné odvození odkazuje na nejnovější zachycení.
Následující příklad obsahuje vzor regulárního výrazu, (?<1>a)(?<1>\1b)*
který předefinuje pojmenovanou skupinu \1. Následující tabulka popisuje jednotlivé vzory v regulárním výrazu.
Vzor | Popis |
---|---|
(?<1>a) |
Porovná znak "a" a přiřadí výsledek skupině zachycení s názvem 1 . |
(?<1>\1b)* |
Porovná nula nebo více výskytů skupiny s názvem 1 "b" a přiřadí výsledek k zachycené skupině s názvem 1 . |
using System;
using System.Text.RegularExpressions;
public class Example
{
public static void Main()
{
string pattern = @"(?<1>a)(?<1>\1b)*";
string input = "aababb";
foreach (Match match in Regex.Matches(input, pattern))
{
Console.WriteLine("Match: " + match.Value);
foreach (Group group in match.Groups)
Console.WriteLine(" Group: " + group.Value);
}
}
}
// The example displays the following output:
// Group: aababb
// Group: abb
Imports System.Text.RegularExpressions
Module Example
Public Sub Main()
Dim pattern As String = "(?<1>a)(?<1>\1b)*"
Dim input As String = "aababb"
For Each match As Match In Regex.Matches(input, pattern)
Console.WriteLine("Match: " + match.Value)
For Each group As Group In match.Groups
Console.WriteLIne(" Group: " + group.Value)
Next
Next
End Sub
End Module
' The example display the following output:
' Group: aababb
' Group: abb
Při porovnávání regulárního výrazu se vstupním řetězcem ("aababb") modul regulárních výrazů provádí následující operace:
Začíná na začátku řetězce a úspěšně odpovídá "a" s výrazem
(?<1>a)
. Hodnota1
skupiny je teď "a".Přejde na druhý znak a úspěšně odpovídá řetězci "ab" s výrazem
\1b
, nebo "ab". Pak přiřadí výsledek "ab" k\1
.Přejde na čtvrtý znak. Výraz
(?<1>\1b)*
se musí shodovat s nulou nebo vícekrát, takže se úspěšně shoduje s řetězcem "abb" s výrazem\1b
. Přiřadí výsledek "abb", zpět .\1
V tomto příkladu je kvantifikátor smyček – vyhodnocuje se opakovaně, *
dokud modul regulárních výrazů neodpovídá vzoru, který definuje. Kvantifikátory smyček nesmažou definice skupin.
Pokud skupina nezachytá žádné podřetězce, není definováno zpětné odvozování této skupiny a nikdy se neshoduje. To je znázorněno vzorem \b(\p{Lu}{2})(\d{2})?(\p{Lu}{2})\b
regulárního výrazu , který je definován takto:
Vzor | Popis |
---|---|
\b |
Zahajte shodu na hranici slova. |
(\p{Lu}{2}) |
Porovná dvě velká písmena. Toto je první zachytávající skupina. |
(\d{2})? |
Porovná žádný nebo jeden výskyt dvou desetinných číslic. Toto je druhá zachytávající skupina. |
(\p{Lu}{2}) |
Porovná dvě velká písmena. Toto je třetí zachytávající skupina. |
\b |
Ukončete shodu na hranici slova. |
Vstupní řetězec se může shodovat s tímto regulárním výrazem, i když nejsou přítomny dvě desetinné číslice definované druhou zachytáváním. Následující příklad ukazuje, že i když je shoda úspěšná, je mezi dvěma úspěšnými skupinami zachycení nalezena prázdná skupina zachycení.
using System;
using System.Text.RegularExpressions;
public class Example
{
public static void Main()
{
string pattern = @"\b(\p{Lu}{2})(\d{2})?(\p{Lu}{2})\b";
string[] inputs = { "AA22ZZ", "AABB" };
foreach (string input in inputs)
{
Match match = Regex.Match(input, pattern);
if (match.Success)
{
Console.WriteLine("Match in {0}: {1}", input, match.Value);
if (match.Groups.Count > 1)
{
for (int ctr = 1; ctr <= match.Groups.Count - 1; ctr++)
{
if (match.Groups[ctr].Success)
Console.WriteLine("Group {0}: {1}",
ctr, match.Groups[ctr].Value);
else
Console.WriteLine("Group {0}: <no match>", ctr);
}
}
}
Console.WriteLine();
}
}
}
// The example displays the following output:
// Match in AA22ZZ: AA22ZZ
// Group 1: AA
// Group 2: 22
// Group 3: ZZ
//
// Match in AABB: AABB
// Group 1: AA
// Group 2: <no match>
// Group 3: BB
Imports System.Text.RegularExpressions
Module Example
Public Sub Main()
Dim pattern As String = "\b(\p{Lu}{2})(\d{2})?(\p{Lu}{2})\b"
Dim inputs() As String = {"AA22ZZ", "AABB"}
For Each input As String In inputs
Dim match As Match = Regex.Match(input, pattern)
If match.Success Then
Console.WriteLine("Match in {0}: {1}", input, match.Value)
If match.Groups.Count > 1 Then
For ctr As Integer = 1 To match.Groups.Count - 1
If match.Groups(ctr).Success Then
Console.WriteLine("Group {0}: {1}", _
ctr, match.Groups(ctr).Value)
Else
Console.WriteLine("Group {0}: <no match>", ctr)
End If
Next
End If
End If
Console.WriteLine()
Next
End Sub
End Module
' The example displays the following output:
' Match in AA22ZZ: AA22ZZ
' Group 1: AA
' Group 2: 22
' Group 3: ZZ
'
' Match in AABB: AABB
' Group 1: AA
' Group 2: <no match>
' Group 3: BB