Share via


Details van het gedrag van reguliere expressies

De .NET regular expression engine is een backtracking regular expression matcher die een traditionele Nondeterministic Finite Automaton (NFA)-engine bevat, zoals die wordt gebruikt door Perl, Python, Emacs en Tcl. Dit onderscheidt het van snellere, maar meer beperkte, pure reguliere expressie Deterministische Finite Automaton (DFA) engines zoals die gevonden in awk, egrep of lex. Dit onderscheidt het ook van gestandaardiseerde, maar langzamere POSIX NFA's. In de volgende sectie worden de drie typen reguliere expressie-engines beschreven en wordt uitgelegd waarom reguliere expressies in .NET worden geïmplementeerd met behulp van een traditionele NFA-engine.

Voordelen van de NFA-engine

Wanneer DFA-engines patroonkoppelingen uitvoeren, wordt de verwerkingsvolgorde aangestuurd door de invoertekenreeks. De engine begint aan het begin van de invoerreeks en gaat sequentieel verder om te bepalen of het volgende teken overeenkomt met het reguliere expressiepatroon. Ze kunnen garanderen dat deze overeenkomen met de langste tekenreeks. Omdat ze nooit hetzelfde teken twee keer testen, bieden DFA-engines geen ondersteuning voor backtracking. Omdat een DFA-engine echter alleen een eindige status bevat, kan deze niet overeenkomen met een patroon met backreferences en omdat er geen expliciete uitbreiding wordt gemaakt, kan er geen subexpressies worden vastgelegd.

In tegenstelling tot DFA-engines, wanneer traditionele NFA-engines patroonkoppelingen uitvoeren, wordt de verwerkingsvolgorde aangestuurd door het reguliere expressiepatroon. Omdat het een bepaald taalelement verwerkt, gebruikt de engine greedy matching; Dat wil gezegd, het komt overeen met zoveel mogelijk van de invoertekenreeks. Maar het slaat ook de status op nadat deze een subexpressie heeft gevonden. Als een overeenkomst uiteindelijk mislukt, kan de engine terugkeren naar een opgeslagen status, zodat er extra overeenkomsten kunnen worden geprobeerd. Dit proces van het afbreken van een geslaagde subexpressieovereenkomst, zodat latere taalelementen in de reguliere expressie ook kunnen overeenkomen, wordt ook wel backtracking genoemd. NFA-engines gebruiken backtracking om alle mogelijke uitbreidingen van een reguliere expressie in een specifieke volgorde te testen en de eerste overeenkomst te accepteren. Omdat een traditionele NFA-engine een specifieke uitbreiding van de reguliere expressie maakt voor een geslaagde overeenkomst, kan deze subexpressieovereenkomsten en overeenkomende backreferences vastleggen. Omdat een traditionele NFA-backtracks echter meerdere keren dezelfde status kan bezoeken als deze via verschillende paden bij de status aankomt. Als gevolg hiervan kan het exponentieel langzaam worden uitgevoerd in het ergste geval. Omdat een traditionele NFA-engine de eerste gevonden overeenkomst accepteert, kan deze ook andere (mogelijk langere) overeenkomsten onvindbaar laten.

POSIX NFA-engines zijn vergelijkbaar met traditionele NFA-engines, behalve dat ze backtracken totdat ze kunnen garanderen dat ze de langste overeenkomst hebben gevonden. Als gevolg hiervan is een POSIX NFA-engine langzamer dan een traditionele NFA-engine en wanneer u een POSIX NFA-engine gebruikt, kunt u geen kortere overeenkomst ten opzichte van een langere engine gebruiken door de volgorde van de backtracking-zoekopdracht te wijzigen.

Traditionele NFA-engines worden door programmeurs begunstigd omdat ze meer controle bieden over tekenreekskoppelingen dan DFA- of POSIX NFA-engines. Hoewel ze in het ergste geval langzaam kunnen worden uitgevoerd, kunt u ze sturen om overeenkomsten te vinden in lineaire of polynomiale tijd door patronen te gebruiken die ambiguïteit verminderen en backtracking beperken. Met andere woorden, hoewel NFA-engines prestaties ruilen voor energie en flexibiliteit, bieden ze in de meeste gevallen goede tot acceptabele prestaties als een reguliere expressie goed is geschreven en vermijdt gevallen waarin backtracking exponentieel de prestaties afneemt.

Mogelijkheden van .NET-engine

Om te profiteren van de voordelen van een traditionele NFA-engine, bevat de .NET reguliere expressie-engine een volledige set constructies waarmee programmeurs de backtracking-engine kunnen sturen. Deze constructies kunnen worden gebruikt om overeenkomsten sneller te vinden of om specifieke uitbreidingen ten opzichte van anderen te bevorderen.

Andere functies van de .NET-engine voor reguliere expressies zijn onder andere:

  • Luie kwantificatoren: ??, *?, , +?{n,m.}? Deze constructies vertellen de backtracking-engine om eerst het minimale aantal herhalingen te doorzoeken. Daarentegen proberen gewone hebzuchtige kwantificatoren eerst het maximum aantal herhalingen te vinden. In het volgende voorbeeld ziet u het verschil tussen de twee. Een reguliere expressie komt overeen met een zin die eindigt op een getal en een vastleggende groep is bedoeld om dat getal te extraheren. De reguliere expressie .+(\d+)\. bevat de hebzuchtige kwantificator .+, waardoor de reguliere expressie-engine alleen het laatste cijfer van het getal vastlegt. De reguliere expressie .+?(\d+)\. bevat daarentegen de luie kwantificator .+?, waardoor de engine voor reguliere expressies het gehele getal vastlegt.

    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
    

    De hebzuchtige en luie versies van deze reguliere expressie worden gedefinieerd zoals wordt weergegeven in de volgende tabel:

    Patroon Beschrijving
    .+ (hebzuchtige kwantificator) Komt overeen met ten minste één exemplaar van een willekeurig teken. Dit zorgt ervoor dat de engine voor reguliere expressies overeenkomt met de hele tekenreeks en vervolgens zo nodig backtrackt om de rest van het patroon te vinden.
    .+? (luie kwantificator) Laat ten minste één exemplaar van een willekeurig teken overeenkomen, maar pas zo weinig mogelijk aan.
    (\d+) Komt overeen met ten minste één numeriek teken en wijs dit toe aan de eerste groep die vastlegt.
    \. Overeenkomst met een punt.

    Zie Kwantificatoren voor meer informatie over luie kwantificatoren.

  • Positieve lookahead: (?=subexpressie). Met deze functie kan de backtracking-engine teruggaan naar dezelfde plek in de tekst nadat deze overeenkomt met een subexpressie. Het is handig om in de tekst te zoeken door meerdere patronen te controleren die vanaf dezelfde positie beginnen. Hiermee kan de engine ook controleren of er een subtekenreeks aan het einde van de overeenkomst bestaat zonder de subtekenreeks in de overeenkomende tekst op te geven. In het volgende voorbeeld wordt een positieve lookahead gebruikt om de woorden in een zin te extraheren die niet worden gevolgd door interpunctiesymbolen.

    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
    

    De reguliere expressie \b[A-Z]+\b(?=\P{P}) wordt gedefinieerd zoals wordt weergegeven in de volgende tabel.

    Patroon Beschrijving
    \b Begin de overeenkomst bij een woordgrens.
    [A-Z]+ Komt een of meer keren overeen met elk alfabetisch teken. Omdat de Regex.Matches methode wordt aangeroepen met de RegexOptions.IgnoreCase optie, is de vergelijking niet hoofdlettergevoelig.
    \b Beëindig de overeenkomst op een woordgrens.
    (?=\P{P}) Kijk vooruit om te bepalen of het volgende teken een interpunctiesymbool is. Als dat niet het is, slaagt de overeenkomst.

    Zie Grouping Constructs voor meer informatie over positieve lookahead-asserties.

  • Negatieve lookahead: (?!subexpressie). Met deze functie wordt de mogelijkheid toegevoegd om alleen een expressie te vinden als een subexpressie niet overeenkomt. Dit is krachtig voor het verwijderen van een zoekopdracht, omdat het vaak eenvoudiger is om een expressie te bieden voor een case die moet worden geëlimineerd dan een expressie voor gevallen die moeten worden opgenomen. Het is bijvoorbeeld moeilijk om een expressie te schrijven voor woorden die niet beginnen met 'niet'. In het volgende voorbeeld wordt een negatieve lookahead gebruikt om deze uit te sluiten.

    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
    

    Het reguliere expressiepatroon \b(?!non)\w+\b wordt gedefinieerd zoals wordt weergegeven in de volgende tabel.

    Patroon Beschrijving
    \b Begin de overeenkomst bij een woordgrens.
    (?!non) Kijk vooruit om ervoor te zorgen dat de huidige tekenreeks niet begint met 'niet'. Als dit het geval is, mislukt de overeenkomst.
    (\w+) Komt overeen met een of meer woordtekens.
    \b Beëindig de overeenkomst op een woordgrens.

    Zie Grouping Constructs voor meer informatie over negatieve lookahead-asserties.

  • Voorwaardelijke evaluatie: (?(expressie)ja|nee) en (?(naam)ja|nee), waarbij de expressie een subexpressie is die overeenkomt, de naam is de naam van een vastleggende groep, ja is de tekenreeks die overeenkomt als de expressie overeenkomt of de naam een geldige, niet-lege vastgelegde groep is en nee is de subexpressie die overeenkomt als de expressie overeenkomt komt niet overeen of de naam is geen geldige, niet-lege vastgelegde groep. Met deze functie kan de engine zoeken met meer dan één alternatief patroon, afhankelijk van het resultaat van een eerdere subexpressieovereenkomst of het resultaat van een assertie met nulbreedte. Dit maakt een krachtigere vorm van backreference mogelijk die bijvoorbeeld overeenkomt met een subexpressie op basis van of een eerdere subexpressie overeenkomt. De reguliere expressie in het volgende voorbeeld komt overeen met alinea's die zijn bedoeld voor zowel openbaar als intern gebruik. Alinea's die alleen zijn bedoeld voor intern gebruik, beginnen met een <PRIVATE> tag. Het patroon voor reguliere expressies ^(?<Pvt>\<PRIVATE\>\s)?(?(Pvt)((\w+\p{P}?\s)+)|((\w+\p{P}?\s)+))\r?$ maakt gebruik van voorwaardelijke evaluatie om de inhoud van alinea's toe te wijzen die bedoeld zijn voor openbaar en intern gebruik om groepen vast te leggen. Deze alinea's kunnen vervolgens anders worden verwerkt.

    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.
    

    Het reguliere expressiepatroon wordt gedefinieerd zoals wordt weergegeven in de volgende tabel.

    Patroon Beschrijving
    ^ Begin de overeenkomst aan het begin van een regel.
    (?<Pvt>\<PRIVATE\>\s)? Kom overeen met nul of één exemplaar van de tekenreeks <PRIVATE> , gevolgd door een spatieteken. Wijs de overeenkomst toe aan een vastleggende groep met de naam Pvt.
    (?(Pvt)((\w+\p{P}?\s)+) Als de Pvt vastleggende groep bestaat, moet u een of meer exemplaren van een of meer woordtekens vergelijken, gevolgd door nul of één leesteken, gevolgd door een spatieteken. Wijs de subtekenreeks toe aan de eerste groep voor vastleggen.
    |((\w+\p{P}?\s)+)) Als de Pvt vastleggende groep niet bestaat, komt u overeen met een of meer exemplaren van een of meer woordtekens gevolgd door nul of één interpunctiescheidingsteken gevolgd door een spatieteken. Wijs de subtekenreeks toe aan de derde groep voor vastleggen.
    \r?$ Komt overeen met het einde van een regel of het einde van de tekenreeks.

    Zie Alternation Constructs voor meer informatie over voorwaardelijke evaluatie.

  • Groepsdefinities verdelen: (?<naam1-naam2-subexpressie>). Met deze functie kan de engine voor reguliere expressies geneste constructies bijhouden, zoals haakjes of haakjes openen en sluiten. Zie Groepeerconstructies voor een voorbeeld.

  • Atomische groepen: (?>subexpressie). Met deze functie kan de backtracking-engine garanderen dat een subexpressie alleen overeenkomt met de eerste overeenkomst die voor die subexpressie is gevonden, alsof de expressie onafhankelijk van de bijbehorende expressie wordt uitgevoerd. Als u deze constructie niet gebruikt, kunnen backtracking-zoekopdrachten van de grotere expressie het gedrag van een subexpressie wijzigen. De reguliere expressie (a+)\w komt bijvoorbeeld overeen met een of meer a-tekens, samen met een woordteken dat volgt op de reeks 'a'-tekens en wijst de reeks 'a'-tekens toe aan de eerste groep die de groep vastlegt. Als het laatste teken van de invoertekenreeks echter ook een 'a' is, wordt deze vergeleken met het \w taalelement en wordt deze niet opgenomen in de vastgelegde groep.

    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
    

    De reguliere expressie ((?>a+))\w voorkomt dit gedrag. Omdat alle opeenvolgende 'a'-tekens overeenkomen zonder backtracking, bevat de eerste vastleggende groep alle opeenvolgende 'a'-tekens. Als de 'a'-tekens niet worden gevolgd door ten minste één ander teken dan 'a', mislukt de overeenkomst.

    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
    

    Zie Groeperingsconstructies voor meer informatie over atomische groepen.

  • Van rechts naar links overeenkomende overeenkomsten, die wordt opgegeven door de RegexOptions.RightToLeft optie aan een Regex klasseconstructor of statische instantiekoppelingsmethode op te geven. Deze functie is handig bij het zoeken van van rechts naar links in plaats van van van links naar rechts, of in gevallen waarin het efficiënter is om een overeenkomst te beginnen aan het rechterdeel van het patroon in plaats van links. Zoals in het volgende voorbeeld wordt geïllustreerd, kan het gebruik van rechts naar links overeenkomende waarden het gedrag van greedy kwantificatoren wijzigen. In het voorbeeld worden twee zoekopdrachten uitgevoerd naar een zin die eindigt op een getal. De links-naar-rechtse zoekopdracht die gebruikmaakt van de greedy kwantificator + komt overeen met een van de zes cijfers in de zin, terwijl de zoekopdracht van rechts naar links overeenkomt met alle zes cijfers. Zie het voorbeeld waarin luie kwantificatoren eerder in deze sectie worden geïllustreerd voor een beschrijving van het reguliere expressiepatroon.

    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
    

    Zie Opties voor reguliere expressies voor meer informatie over rechts-naar-links-overeenkomsten.

  • Positieve en negatieve lookbehind: (?<=subexpressie) voor positieve lookbehind en (?<!subexpressie) voor negatieve lookbehind. Deze functie is vergelijkbaar met lookahead, die eerder in dit onderwerp wordt besproken. Omdat de engine voor reguliere expressies volledige overeenkomsten van rechts naar links toestaat, staan reguliere expressies onbeperkte lookbehinds toe. Positieve en negatieve lookbehind kan ook worden gebruikt om geneste kwantificatoren te voorkomen wanneer de geneste subexpressie een superset van een buitenste expressie is. Reguliere expressies met dergelijke geneste kwantificatoren bieden vaak slechte prestaties. In het volgende voorbeeld wordt bijvoorbeeld gecontroleerd of een tekenreeks begint en eindigt met een alfanumerieke teken en dat een ander teken in de tekenreeks een van een grotere subset is. Het vormt een deel van de reguliere expressie die wordt gebruikt om e-mailadressen te valideren; Zie Procedure voor meer informatie: Controleren of tekenreeksen een geldige e-mailindeling hebben.

    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
    

    De reguliere expressie ^[A-Z0-9]([-!#$%&'.*+/=?^`{}|~\w])*(?<=[A-Z0-9])$ wordt gedefinieerd zoals wordt weergegeven in de volgende tabel.

    Patroon Beschrijving
    ^ Begin de overeenkomst aan het begin van de tekenreeks.
    [A-Z0-9] Komt overeen met een numeriek of alfanumerieke teken. (De vergelijking is niet hoofdlettergevoelig.)
    ([-!#$%&'.*+/=?^`{}|~\w])* Kom overeen met nul of meer exemplaren van een woordteken of een van de volgende tekens: -, !, #, $, %, &, ', ., *, +, /, =, ?, ^, ', {, }, |of ~.
    (?<=[A-Z0-9]) Kijk achter het vorige teken, dat numeriek of alfanumeriek moet zijn. (De vergelijking is niet hoofdlettergevoelig.)
    $ Beëindig de overeenkomst aan het einde van de tekenreeks.

    Zie Groeperingsconstructies voor meer informatie over positieve en negatieve lookbehind.

Title Beschrijving
Backtracking Biedt informatie over hoe backtracking-vertakkingen voor reguliere expressies alternatieve overeenkomsten kunnen vinden.
Compilatie en hergebruik Bevat informatie over het compileren en hergebruiken van reguliere expressies om de prestaties te verbeteren.
Reguliere .NET-expressies Biedt een overzicht van het aspect van de programmeertaal van reguliere expressies.
Het objectmodel van de reguliere expressie Bevat informatie- en codevoorbeelden die illustreren hoe u de reguliere expressieklassen gebruikt.
Reguliere expressietaal - Snelzoekgids Bevat informatie over de set tekens, operators en constructies die u kunt gebruiken om reguliere expressies te definiëren.

Verwijzing