Udostępnij za pośrednictwem


Szczegóły zachowania wyrażenia regularnego

Aparat wyrażeń regularnych platformy .NET jest modułem matcher wyrażeń regularnych wycofywania, który zawiera tradycyjny aparat Finite Automaton (NFA, Nondeterministic Finite Automaton), taki jak używany przez perl, Python, Emacs i Tcl. To odróżnia go od szybszych, ale bardziej ograniczonych, czystych aparatów deterministycznego automatu finickiego (DFA), takich jak te występujące w niewygodach, egrep lub lex. Różni się to również od ustandaryzowanych, ale wolniejszych, POSIX NFAs. W poniższej sekcji opisano trzy typy aparatów wyrażeń regularnych i wyjaśniono, dlaczego wyrażenia regularne na platformie .NET są implementowane przy użyciu tradycyjnego aparatu NFA.

Zalety aparatu NFA

Gdy aparaty DFA wykonują dopasowywanie wzorców, ich kolejność przetwarzania jest sterowana ciągiem wejściowym. Aparat rozpoczyna się na początku ciągu wejściowego i przechodzi sekwencyjnie, aby określić, czy następny znak jest zgodny ze wzorcem wyrażenia regularnego. Mogą zagwarantować dopasowanie najdłuższego możliwego ciągu. Ponieważ nigdy nie testują tego samego znaku dwa razy, aparaty DFA nie obsługują wycofywania. Jednak ze względu na to, że aparat DFA zawiera tylko stan skończony, nie może dopasować wzorca z backreferences i ponieważ nie tworzy jawnego rozszerzenia, nie może przechwytywać podwyrażenia.

W przeciwieństwie do aparatów DFA, gdy tradycyjne aparaty NFA wykonują dopasowywanie wzorców, ich kolejność przetwarzania jest napędzana przez wzorzec wyrażenia regularnego. W miarę przetwarzania określonego elementu języka aparat używa chciwego dopasowania; oznacza to, że pasuje do jak najwięcej ciągu wejściowego, jak to możliwe. Ale również zapisuje swój stan po pomyślnym dopasowaniu podexpressionu. Jeśli dopasowanie ostatecznie zakończy się niepowodzeniem, aparat może powrócić do zapisanego stanu, aby można było spróbować dodatkowych dopasowań. Ten proces porzucania pomyślnego dopasowania podwyrażenia, tak aby późniejsze elementy języka w wyrażeniu regularnym mogły być również zgodne, jest nazywane wycofywaniem. Aparaty NFA używają wycofywania do testowania wszystkich możliwych rozszerzeń wyrażenia regularnego w określonej kolejności i akceptowania pierwszego dopasowania. Ponieważ tradycyjny aparat NFA tworzy określoną ekspansję wyrażenia regularnego dla pomyślnego dopasowania, może przechwytywać dopasowania podwyrażenia i dopasowywać backreferences. Jednak ze względu na to, że tradycyjne wycofywanie uwierzytelniania NFA może odwiedzać ten sam stan wiele razy, jeśli dociera do stanu na różnych ścieżkach. W rezultacie może działać wykładniczo powoli w najgorszym przypadku. Ponieważ tradycyjny aparat NFA akceptuje pierwsze znalezione dopasowanie, może również pozostawić inne (prawdopodobnie dłuższe) dopasowania nieodkryte.

Silniki NFA POSIX są jak tradycyjne silniki NFA, z tą różnicą, że nadal wracają do momentu, gdy będą mogły zagwarantować, że odnalazły najdłuższy możliwy mecz. W rezultacie aparat NFA POSIX jest wolniejszy niż tradycyjny aparat NFA, a gdy używasz aparatu NFA POSIX, nie można faworyzować krótszego dopasowania w dłuższym, zmieniając kolejność wyszukiwania wycofywania.

Tradycyjne aparaty NFA są preferowane przez programistów, ponieważ oferują większą kontrolę nad dopasowaniem ciągów niż silniki NFA DFA lub POSIX. Chociaż w najgorszym przypadku mogą działać powoli, można kierować je w celu znalezienia dopasowań w czasie liniowym lub wielomianowym, używając wzorców, które zmniejszają niejednoznaczności i ograniczają wycofywanie. Innymi słowy, chociaż silniki NFA handlują wydajnością dla mocy i elastyczności, w większości przypadków oferują one dobrą do akceptowalnej wydajności, jeśli wyrażenie regularne jest dobrze napisane i unika przypadków, w których wycofywanie obniża wydajność wykładniczo.

Uwaga

Aby uzyskać informacje na temat kary za wydajność spowodowane nadmiernym wycofywaniem i sposobami tworzenia wyrażenia regularnego w celu ich obejścia, zobacz Wycofywanie.

Możliwości aparatu .NET

Aby skorzystać z zalet tradycyjnego aparatu NFA, aparat wyrażeń regularnych platformy .NET zawiera kompletny zestaw konstrukcji, aby umożliwić programistom kierowanie aparatem wycofywania. Te konstrukcje mogą służyć do znajdowania dopasowań szybciej lub faworyzowania określonych rozszerzeń nad innymi.

Inne funkcje aparatu wyrażeń regularnych platformy .NET obejmują następujące elementy:

  • Kwantyfikatory z opóźnieniem: ??, *?, +?, {n,m.}? Te konstrukcje informują aparat wycofywania, aby najpierw przeszukał minimalną liczbę powtórzeń. Natomiast zwykłe kwantyfikatory chciwości próbują najpierw dopasować maksymalną liczbę powtórzeń. Poniższy przykład ilustruje różnicę między nimi. Wyrażenie regularne pasuje do zdania kończącego się liczbą, a grupa przechwytywania ma na celu wyodrębnienie tej liczby. Wyrażenie .+(\d+)\. regularne zawiera chciwy kwantyfikator .+, co powoduje, że aparat wyrażeń regularnych przechwytuje tylko ostatnią cyfrę liczby. Natomiast wyrażenie .+?(\d+)\. regularne zawiera leniwy kwantyfikator .+?, co powoduje, że aparat wyrażeń regularnych przechwytuje całą liczbę.

    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
    

    Chciwe i leniwe wersje tego wyrażenia regularnego są zdefiniowane, jak pokazano w poniższej tabeli:

    Wzorzec opis
    .+ (chciwy kwantyfikator) Dopasuj co najmniej jedno wystąpienie dowolnego znaku. Powoduje to dopasowanie aparatu wyrażeń regularnych do całego ciągu, a następnie do wycofywania zgodnie z potrzebami, aby dopasować pozostałą część wzorca.
    .+? (kwantyfikator z opóźnieniem) Dopasuj co najmniej jedno wystąpienie dowolnego znaku, ale dopasuj je tak mało, jak to możliwe.
    (\d+) Dopasuj co najmniej jeden znak liczbowy i przypisz go do pierwszej grupy przechwytywania.
    \. Dopasuj kropkę.

    Aby uzyskać więcej informacji na temat leniwych kwantyfikatorów, zobacz Quantifiers.

  • Pozytywne spojrzenie: (?=podwyrażenie). Ta funkcja umożliwia aparatowi wycofywania powrót do tego samego miejsca w tekście po dopasowaniu podexpressionu. Przydatne jest wyszukiwanie w całym tekście przez zweryfikowanie wielu wzorców, które zaczynają się od tej samej pozycji. Umożliwia również aparatowi sprawdzenie, czy podciąg istnieje na końcu dopasowania bez uwzględniania podciągów w dopasowanym tekście. W poniższym przykładzie użyto pozytywnego spojrzenia, aby wyodrębnić wyrazy w zdaniu, które nie są zgodne z symbolami interpunkcyjnymi.

    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
    

    Wyrażenie \b[A-Z]+\b(?=\P{P}) regularne jest definiowane, jak pokazano w poniższej tabeli.

    Wzorzec opis
    \b Rozpoczyna dopasowanie na granicy wyrazu.
    [A-Z]+ Dopasuj dowolny znak alfabetyczny co najmniej raz. Regex.Matches Ponieważ metoda jest wywoływana z opcjąRegexOptions.IgnoreCase, porównanie jest bez uwzględniania wielkości liter.
    \b Kończy dopasowanie na granicy wyrazu.
    (?=\P{P}) Przyjrzyj się, czy następny znak jest symbolem interpunkcyjnym. Jeśli tak nie jest, dopasowanie zakończy się pomyślnie.

    Aby uzyskać więcej informacji na temat pozytywnych asercji lookahead, zobacz Grouping Constructs (Konstrukcje grupowania).

  • Negatywne spojrzenie: (?!podwyrażenie). Ta funkcja dodaje możliwość dopasowania wyrażenia tylko wtedy, gdy wyrażenie podrzędne nie jest zgodne. Jest to zaawansowane w przypadku oczyszczania wyszukiwania, ponieważ często łatwiej jest podać wyrażenie dla przypadku, które należy wyeliminować niż wyrażenie dla przypadków, które należy uwzględnić. Na przykład trudno jest napisać wyrażenie dla wyrazów, które nie zaczynają się od "non". W poniższym przykładzie użyto negatywnego spojrzenia, aby je wykluczyć.

    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
    

    Wzorzec \b(?!non)\w+\b wyrażenia regularnego jest zdefiniowany, jak pokazano w poniższej tabeli.

    Wzorzec opis
    \b Rozpoczyna dopasowanie na granicy wyrazu.
    (?!non) Spójrz dalej, aby upewnić się, że bieżący ciąg nie zaczyna się od "non". Jeśli tak, dopasowanie zakończy się niepowodzeniem.
    (\w+) Dopasowuje co najmniej jeden znak słowa.
    \b Kończy dopasowanie na granicy wyrazu.

    Aby uzyskać więcej informacji na temat negatywnych asercji, zobacz Grouping Constructs (Konstrukcje grupowania).

  • Ocena warunkowa: (?(wyrażenie)tak nie) i (?(nazwa)tak||nie), gdzie wyrażenie jest podwyrażeniem do dopasowania, nazwa jest nazwą grupy przechwytywania, tak jest ciąg do dopasowania, jeśli wyrażenie jest zgodne, lub nazwa jest prawidłową, niepustą przechwyconą grupą, a nie jest podwyrażeniem, które ma być zgodne, jeśli wyrażenie jest zgodne jest niezgodna lub nazwa nie jest prawidłową, niepustą grupą przechwyconą. Ta funkcja umożliwia aparatowi wyszukiwanie przy użyciu więcej niż jednego alternatywnego wzorca, w zależności od wyniku poprzedniego wyrażenia podrzędnego lub wyniku asercji o zerowej szerokości. Pozwala to na bardziej zaawansowaną formę wnioskowania wstecznego, która pozwala na przykład dopasowanie podwyrażenia na podstawie tego, czy poprzednie podwyrażenie zostało dopasowane. Wyrażenie regularne w poniższym przykładzie pasuje do akapitów przeznaczonych zarówno do użytku publicznego, jak i wewnętrznego. Akapity przeznaczone tylko do użytku wewnętrznego zaczynają się od tagu <PRIVATE> . Wzorzec ^(?<Pvt>\<PRIVATE\>\s)?(?(Pvt)((\w+\p{P}?\s)+)|((\w+\p{P}?\s)+))\r?$ wyrażenia regularnego używa oceny warunkowej do przypisania zawartości akapitów przeznaczonych do użytku publicznego i do użytku wewnętrznego w celu oddzielenia grup przechwytywania. Te akapity można następnie obsługiwać inaczej.

    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.
    

    Wzorzec wyrażenia regularnego jest zdefiniowany, jak pokazano w poniższej tabeli.

    Wzorzec opis
    ^ Rozpocznij dopasowanie na początku wiersza.
    (?<Pvt>\<PRIVATE\>\s)? Dopasuj zero lub jedno wystąpienie ciągu <PRIVATE> , po którym następuje znak odstępu. Przypisz dopasowanie do grupy przechwytywania o nazwie Pvt.
    (?(Pvt)((\w+\p{P}?\s)+) Pvt Jeśli grupa przechwytywania istnieje, dopasuj co najmniej jedno wystąpienie co najmniej jednego znaku słowa, po którym następuje zero lub jeden separator interpunkcyjny, po którym następuje znak odstępu. Przypisz podciąg do pierwszej grupy przechwytywania.
    |((\w+\p{P}?\s)+)) Pvt Jeśli grupa przechwytywania nie istnieje, dopasuj jedno lub więcej wystąpień jednego lub więcej znaków słowa, po którym następuje zero lub jeden separator interpunkcyjny, po którym następuje znak odstępu. Przypisz podciąg do trzeciej grupy przechwytywania.
    \r?$ Dopasuj koniec wiersza lub końca ciągu.

    Aby uzyskać więcej informacji na temat oceny warunkowej, zobacz Konstrukcje zmiany.

  • Równoważenie definicji grup: (?<name1-name2> subexpression). Ta funkcja umożliwia aparatowi wyrażeń regularnych śledzenie zagnieżdżonych konstrukcji, takich jak nawiasy lub nawiasy otwierające i zamykające. Przykład można znaleźć w temacie Grouping Constructs (Konstrukcje grupowania).

  • Grupy niepodzielne: (?>podexpression). Ta funkcja pozwala aparatowi wycofywania zagwarantować, że wyrażenie podrzędne jest zgodne tylko z pierwszym dopasowaniem znalezionym dla tego wyrażenia podrzędnego, tak jakby wyrażenie było uruchomione niezależnie od jego wyrażenia zawierającego. Jeśli nie używasz tej konstrukcji, wycofywanie wyszukiwań z większego wyrażenia może zmienić zachowanie podexpressionu. Na przykład wyrażenie (a+)\w regularne pasuje do co najmniej jednego znaku "a" wraz z znakiem słowa, który jest zgodny z sekwencją znaków "a" i przypisuje sekwencję znaków "a" do pierwszej grupy przechwytywania. Jeśli jednak końcowy znak ciągu wejściowego jest również "a", jest zgodny z \w elementem języka i nie jest uwzględniony w przechwyconej grupie.

    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
    

    Wyrażenie ((?>a+))\w regularne uniemożliwia to zachowanie. Ponieważ wszystkie kolejne znaki "a" są dopasowywane bez wycofywania, pierwsza grupa przechwytywania zawiera wszystkie kolejne znaki "a". Jeśli znaki "a" nie są obserwowane przez co najmniej jeden znak inny niż "a", dopasowanie kończy się niepowodzeniem.

    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
    

    Aby uzyskać więcej informacji na temat grup niepodzielnych, zobacz Grouping Constructs (Konstrukcje grupowania).

  • Dopasowanie od prawej do lewej, które jest określane przez podanie opcji Regex konstruktora klasy lub metody dopasowywania RegexOptions.RightToLeft statycznego wystąpienia. Ta funkcja jest przydatna podczas wyszukiwania od prawej do lewej zamiast od lewej do prawej lub w przypadkach, gdy jest bardziej wydajne, aby rozpocząć dopasowanie w prawej części wzorca zamiast po lewej stronie. Jak pokazano w poniższym przykładzie, użycie dopasowania od prawej do lewej może zmienić zachowanie chciwych kwantyfikatorów. W przykładzie są prowadzone dwa wyszukiwania w zdaniu kończącym się liczbą. Wyszukiwanie od lewej do prawej, które używa chciwego kwantyfikatora + , pasuje do jednej z sześciu cyfr w zdaniu, podczas gdy wyszukiwanie od prawej do lewej pasuje do wszystkich sześciu cyfr. Aby zapoznać się z opisem wzorca wyrażenia regularnego, zobacz przykład ilustrujący kwantyfikatory z opóźnieniem we wcześniejszej części tej sekcji.

    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
    

    Aby uzyskać więcej informacji na temat dopasowywania od prawej do lewej, zobacz Opcje wyrażeń regularnych.

  • Dodatnie i negatywne spojrzeniebehind: (?<=podwyrażenie) dla pozytywnego wyglądu i (?<!podwyrażenie) dla ujemnego wyglądu. Ta funkcja jest podobna do lookahead, która została omówiona wcześniej w tym temacie. Ponieważ aparat wyrażeń regularnych umożliwia pełne dopasowywanie od prawej do lewej, wyrażenia regularne umożliwiają nieograniczone wyszukiwanie. Dodatni i ujemny wygląd można również użyć, aby uniknąć zagnieżdżania kwantyfikatorów, gdy zagnieżdżone podwyrażenie jest nadzbiorem wyrażenia zewnętrznego. Wyrażenia regularne z takimi zagnieżdżonym kwantyfikatory często oferują niską wydajność. Na przykład poniższy przykład sprawdza, czy ciąg rozpoczyna się i kończy się znakiem alfanumerycznym, a każdy inny znak w ciągu jest jednym z większego podzestawu. Tworzy część wyrażenia regularnego używanego do weryfikowania adresów e-mail; Aby uzyskać więcej informacji, zobacz How to: Verify that Strings Are in Valid Email Format (Instrukcje: sprawdzanie, czy ciągi są w prawidłowym formacie poczty e-mail).

    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
    

    Wyrażenie ^[A-Z0-9]([-!#$%&'.*+/=?^`{}|~\w])*(?<=[A-Z0-9])$ regularne jest definiowane, jak pokazano w poniższej tabeli.

    Wzorzec opis
    ^ Rozpocznij dopasowanie na początku ciągu.
    [A-Z0-9] Dopasuj dowolny znak liczbowy lub alfanumeryczny. (Porównanie jest bez uwzględniania wielkości liter).
    ([-!#$%&'.*+/=?^`{}|~\w])* Dopasuj zero lub więcej wystąpień dowolnego znaku słowa lub dowolny z następujących znaków: -, !, #, $, %, &, ', ., *, +, /, =, ?, ^, ', {, }, |lub ~.
    (?<=[A-Z0-9]) Przyjrzyj się poprzedniemu znakowi, który musi być numeryczny lub alfanumeryczny. (Porównanie jest bez uwzględniania wielkości liter).
    $ Zakończ dopasowanie na końcu ciągu.

    Aby uzyskać więcej informacji na temat pozytywnego i negatywnego wyglądu, zobacz Konstrukcje grupowania.

Nazwa opis
Śledzenie wsteczne Zawiera informacje o tym, jak gałęzie wycofywania wyrażeń regularnych w celu znalezienia alternatywnych dopasowań.
Kompilacja i ponowne używanie Zawiera informacje o kompilowaniu i ponownym użyciu wyrażeń regularnych w celu zwiększenia wydajności.
Wyrażenia regularne platformy .NET Zawiera omówienie aspektu języka programowania w wyrażeniach regularnych.
Model obiektów wyrażeń regularnych Zawiera informacje i przykłady kodu ilustrujące sposób używania klas wyrażeń regularnych.
Język wyrażeń regularnych — podręczny wykaz Zawiera informacje o zestawie znaków, operatorów i konstrukcji, których można użyć do definiowania wyrażeń regularnych.

Odwołanie