Backreference-konstruktioner i reguljära uttryck
Backreferences är ett bekvämt sätt att identifiera ett upprepat tecken eller delsträngar i en sträng. Om indatasträngen till exempel innehåller flera förekomster av en godtycklig delsträng kan du matcha den första förekomsten med en insamlingsgrupp och sedan använda en backreference för att matcha efterföljande förekomster av understrängen.
Kommentar
En separat syntax används för att referera till namngivna och numrerade insamlingsgrupper i ersättningssträngar. Mer information finns i Substitutioner.
.NET definierar separata språkelement för att referera till numrerade och namngivna insamlingsgrupper. Mer information om hur du samlar in grupper finns i Grupperingskonstruktioner.
Numrerade backreferences
En numrerad backreference använder följande syntax:
\
nummer
där talet är ordningstalet för insamlingsgruppen i det reguljära uttrycket. Matchar till exempel \4
innehållet i den fjärde insamlingsgruppen. Om talet inte definieras i mönstret för reguljära uttryck uppstår ett parsningsfel och motorn för reguljära uttryck genererar en ArgumentException. Det reguljära uttrycket \b(\w+)\s\1
är till exempel giltigt, eftersom (\w+)
det är den första och enda insamlingsgruppen i uttrycket. Å andra sidan \b(\w+)\s\2
är ogiltigt och genererar ett argumentfel, eftersom det inte finns någon samlande grupp numrerad \2
. Om talet dessutom identifierar en samlande grupp i en viss ordningstalsposition, men den samlande gruppen har tilldelats ett numeriskt namn som skiljer sig från dess ordningstalsposition, genererar parsern för reguljära uttryck också en ArgumentException.
Observera tvetydigheten mellan oktala escape-koder (till exempel \16
) och \
antal backreferences som använder samma notation. Den här tvetydigheten löses på följande sätt:
Uttrycken
\1
genom\9
tolkas alltid som backreferences och inte som oktala koder.Om den första siffran i ett multidigit-uttryck är 8 eller 9 (till exempel
\80
eller\91
), tolkas uttrycket som en literal.Uttryck från
\10
och större betraktas som backreferences om det finns en backreference som motsvarar det talet. Annars tolkas de som oktala koder.Om ett reguljärt uttryck innehåller en backreference till ett odefinierat gruppnummer uppstår ett parsningsfel och motorn för reguljära uttryck genererar en ArgumentException.
Om tvetydigheten är ett problem kan du använda \k<
namnkommenteringen>
, som är tvetydig och inte kan förväxlas med oktala teckenkoder. På samma sätt är hexadecimala koder som \xdd
entydiga och kan inte förväxlas med backreferences.
I följande exempel hittas dubbla ordtecken i en sträng. Det definierar ett reguljärt uttryck, (\w)\1
, som består av följande element.
Element | Description |
---|---|
(\w) |
Matcha ett ordtecken och tilldela det till den första insamlingsgruppen. |
\1 |
Matcha nästa tecken som är samma som värdet för den första insamlingsgruppen. |
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.
Namngivna backreferences
En namngiven backreference definieras med hjälp av följande syntax:
\k<
Namn >
eller:
\k'
Namn '
där namnet är namnet på en insamlingsgrupp som definierats i mönstret för reguljära uttryck. Om namnet inte definieras i mönstret för reguljära uttryck uppstår ett parsningsfel och motorn för reguljära uttryck genererar en ArgumentException.
I följande exempel hittas dubbla ordtecken i en sträng. Det definierar ett reguljärt uttryck, (?<char>\w)\k<char>
, som består av följande element.
Element | Description |
---|---|
(?<char>\w) |
Matcha ett ordtecken och tilldela det till en samlande grupp med namnet char . |
\k<char> |
Matcha nästa tecken som är samma som värdet för insamlingsgruppen char . |
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.
Namngivna numeriska backreferences
I en namngiven backreference med \k
kan namnet också vara strängrepresentationen av ett tal. I följande exempel används till exempel reguljära uttryck (?<2>\w)\k<2>
för att hitta dubbla ordtecken i en sträng. I det här fallet definierar exemplet en insamlingsgrupp som uttryckligen heter "2" och backreference heter "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.
Om namnet är strängrepresentationen av ett tal och ingen insamlingsgrupp har det namnet, \k<
är namnet>
samma som backreference-talet\
, där talet är ordningstalet för avbildningen. I följande exempel finns det en enda insamlingsgrupp med namnet char
. Backreference-konstruktionen refererar till den som \k<1>
. Som utdata från exemplet visar lyckas anropet Regex.IsMatch till eftersom char
är den första insamlingsgruppen.
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
Men om namnet är strängrepresentationen av ett tal och insamlingsgruppen i den positionen uttryckligen har tilldelats ett numeriskt namn, kan den reguljära uttrycksparsern inte identifiera insamlingsgruppen med dess ordningstal. I stället genererar den en ArgumentException. Den enda insamlingsgruppen i följande exempel heter "2". Eftersom konstruktionen \k
används för att definiera en backreference med namnet "1" kan den reguljära uttrycksparsern inte identifiera den första insamlingsgruppen och utlöser ett undantag.
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
Vad backreferences matchar
En backreference refererar till den senaste definitionen av en grupp (definitionen närmast till vänster, vid matchning från vänster till höger). När en grupp gör flera avbildningar refererar en backreference till den senaste avbildningen.
I följande exempel finns ett mönster för reguljära uttryck, (?<1>a)(?<1>\1b)*
, som omdefinierar gruppen \1 med namnet . I följande tabell beskrivs varje mönster i det reguljära uttrycket.
Mönster | beskrivning |
---|---|
(?<1>a) |
Matcha tecknet "a" och tilldela resultatet till insamlingsgruppen med namnet 1 . |
(?<1>\1b)* |
Matcha noll eller fler förekomster av gruppen med namnet 1 tillsammans med "b" och tilldela resultatet till insamlingsgruppen med namnet 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
När du jämför det reguljära uttrycket med indatasträngen ("aababb" utför motorn för reguljära uttryck följande åtgärder:
Den börjar i början av strängen och matchar "a" med uttrycket
(?<1>a)
. Värdet för1
gruppen är nu "a".Det avancerar till det andra tecknet och matchar strängen "ab" med uttrycket
\1b
, eller "ab". Sedan tilldelas resultatet "ab" till\1
.Det avancerar till det fjärde tecknet. Uttrycket
(?<1>\1b)*
ska matchas noll eller fler gånger, så det matchar strängen "abb" med uttrycket\1b
. Det tilldelar resultatet , "abb", tillbaka till\1
.
I det här exemplet *
är en loopande kvantifierare – den utvärderas upprepade gånger tills motorn för reguljära uttryck inte kan matcha det mönster som definieras. Loopa kvantifierare rensar inte gruppdefinitioner.
Om en grupp inte har samlat in några understrängar är en backreference till den gruppen odefinierad och matchar aldrig. Detta illustreras av det reguljära uttrycksmönstret \b(\p{Lu}{2})(\d{2})?(\p{Lu}{2})\b
, som definieras på följande sätt:
Mönster | beskrivning |
---|---|
\b |
Börja matcha på en ordgräns. |
(\p{Lu}{2}) |
Matcha två versaler. Det här är den första insamlingsgruppen. |
(\d{2})? |
Matcha noll eller en förekomst av två decimalsiffror. Det här är den andra insamlingsgruppen. |
(\p{Lu}{2}) |
Matcha två versaler. Det här är den tredje insamlingsgruppen. |
\b |
Avsluta matchningen på en ordgräns. |
En indatasträng kan matcha det här reguljära uttrycket även om de två decimaltalen som definieras av den andra insamlingsgruppen inte finns. Följande exempel visar att även om matchningen lyckas, hittas en tom insamlingsgrupp mellan två lyckade insamlingsgrupper.
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