Konstrukce zpětných odkazů
Zpětné odkazy poskytují pohodlný způsob pro identifikaci opakovaného znaku nebo podřetězce v rámci řetězce. Například pokud vstupní řetězec obsahuje více výskytů libovolného dílčího řetězce, můžete porovnat první výskyt se zachycující skupinou a potom použít zpětný odkaz pro porovnání dalších výskytů podřetězce.
Poznámka |
---|
Pro odkazování na pojmenované a číslované zachytávající skupiny v řetězci pro nahrazení se používá samostatná syntaxe. Další informace naleznete v tématu Substituce. |
Rozhraní .NET Framework definuje samostatné prvky jazyka pro odkazování na číslované a pojmenované zachytávající skupiny. Další informace o zachycujících skupinách naleznete v tématu Seskupovací konstrukce.
Číslované zpětné odkazy
Číslovaný zpětný odkaz používá následující syntaxi:
\číslo
kde number je pořadové číslo pozice zachytávající skupiny v regulárním výrazu. Například \4 odpovídá obsahu čtvrté zachytávající skupiny. Pokud není number definováno ve vzorku regulárního výrazu, dojde k chybě analýzy a modul regulárních výrazů vyvolá ArgumentException. Například regulární výraz \b(\w+)\s\1 je platný, protože (\w+) je první a jediná zachytávající skupina ve výrazu. Na druhé straně \b(\w+)\s\2 je neplatná a vyvolá výjimku argumentu, protože není k dispozici žádná zachytávající skupina s číslem \2.
Všimněte si nejednoznačnosti mezi osmičkovými kódy (například zpětné odkazy \16) a \number používajících stejný zápis. Tato nejednoznačnosti je vyřešena následujícím způsobem:
Výrazy \1 až \9 jsou vždy interpretovány jako zpětné odkazy a nikoli jako osmičkové kódy.
Je-li první číslice vícečíslicového výrazu 8 nebo 9 (například \80 nebo \91), je výraz interpretován jako literální.
Výrazy z \10 a větší jsou považovány za zpětné odkazy, pokud existuje zpětný odkaz odpovídající danému číslu. Jinak jsou interpretovány jako osmičkové kódy.
Pokud regulární výraz obsahuje zpětný odkaz na nedefinované číslo skupiny, dojde k chybě analýzy a modul regulárních výrazů vyvolá ArgumentException.
Pokud je nejednoznačnost problémem, můžete použít zápis \k<name>, což je jednoznačné a nemůže být zaměněno s osmičkovými kódy. Podobně kódy v šestnáctkové soustavě například \xdd jsou jednoznačné a nelze je zaměňovat se zpětnými odkazy.
Následující příklad vyhledá zdvojené znaky slova v řetězci. Regulární výraz definuje (\w)\1, který se skládá z následujících prvků.
Prvek |
Popis |
---|---|
(\w) |
Porovná znak slova a přiřadí jej k první záchytávající skupině. |
\1 |
Porovná další znak, který je stejný jako hodnota první zachycující skupiny. |
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.
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.
Pojmenované zpětné odkazy
Pojmenované zpětné odkazy jsou definovány pomocí následující syntaxe:
\k<název>
nebo:
\k'název'
kde name je název zachytávající skupiny definované ve vzorku regulárního výrazu. Pokud není name definováno ve vzorku regulárního výrazu, dojde k chybě analýzy a modul regulárních výrazů vyvolá ArgumentException.
Následující příklad vyhledá zdvojené znaky slova v řetězci. Regulární výraz definuje (?<char>\w)\k<char>, který se skládá z následujících prvků.
Prvek |
Popis |
---|---|
(?<char>\w) |
Porovná znak slova a přiřadí jej k záchytávající skupině s názvem char. |
\k<char> |
Porovná další znak, který je stejný jako hodnota zachycující skupiny char. |
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.
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.
Všimněte si, že name může být také řetězcovým vyjádřením čísla. Například následující příklad používá regulární výraz (?<2>\w)\k<2> pro nalezení zdvojených znaků slova v řetězci.
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.
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.
Co porovnávají zpětné odkazy
Zpětný odkaz odkazuje na nejnovější definici skupiny (definice bezprostředně nalevo při porovnávání zleva doprava). Pokud skupina provádí více zachycení, zpětný odkaz odkazuje na nejnovější zachycení.
Následující příklad obsahuje vzorek regulárního výrazu (?<1>a)(?<1>\1b)*, který předefinuje skupinu s názvem \1. Následující tabulka popisuje každý vzorek v regulárním výrazu.
Maska |
Popis |
---|---|
(?<1>a) |
Porovná znak a a přiřadí výsledek do zachycující skupiny s názvem 1. |
(?<1>\1b)* |
Porovná 0 nebo 1 výskyt skupiny s názvem 1 spolu s b a přiřadí výsledek do zachycující skupiny s názvem 1. |
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
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
Při porovnávání regulárního výrazu se vstupním řetězcem aababb, modul regulárních výrazů provede následující operace:
Začne na začátku řetězce a úspěšně porovná a s výrazem (?<1>a). Hodnota skupiny 1 je nyní a.
Přejde na druhý znak a úspěšně porovná řetězec ab s výrazem \1b nebo ab. Potom přiřadí výsledek ab do \1.
Přejde na čtvrtý znak. Výraz (?<1>\1b) je porovnán nula nebo vícekrát, tak aby úspěšně porovnal řetězec abb a výraz \1b. Přiřadí výsledek abb zpět do \1.
V tomto příkladu je * kvantifikátor opakování. Je vyhodnocován opakovaně dokud modul regulárních výrazů nemůže porovnat vzorek, který definuje. Kvantifikátory opakování neruší definice skupin.
Pokud skupina nezachytila žádný podřetězec, zpětný odkaz na tuto skupinu je nedefinován a není nikdy porovnáván. To je znázorněno vzorkem regulárního výrazu \b(\p{Lu}{2})(\d{2})?(\p{Lu}{2})\b, který je definován takto:
Maska |
Popis |
---|---|
\b |
Začne porovnání na hranici slova. |
(\p{Lu}{2}) |
Porovná dvě velká písmena. Toto je první zachytávající skupina. |
(\d{2})? |
Porovná nula nebo jeden výskyt dvou desítkových číslic. Toto je druhá zachytávající skupina. |
(\p{Lu}{2}) |
Porovná dvě velká písmena. Toto je třetí zachycující skupina. |
\b |
Ukončí porovnání na hranici slova. |
Vstupní řetězec může odpovídat tomuto regulárnímu výrazu i v případě, že dvě desítkové číslice, které jsou definované druhou zachycující skupinou nejsou k dispozici. Následující příklad ukazuje, že i v případě, že je porovnávání úspěšné, je prázdná zachycující skupina nalezena mezi dvěmi úspěšnými zachycujícími skupinami.
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
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