Freigeben über


Backtracking

Eine Rückverfolgung tritt ein, wenn ein Muster eines regulären Ausdrucks optionale Quantifizierer oder Alternierungskonstrukte enthält und das Modul für reguläre Ausdrücke in einen zuvor gespeicherten Zustand zurückkehrt, um die Suche nach einer Übereinstimmung fortzusetzen. Die Rückverfolgung ist für die Leistungsfähigkeit regulärer Ausdrücke von zentraler Bedeutung. Sie ermöglicht flexible und leistungsstarke Ausdrücke, die höchst komplexen Muster entsprechen können. Diese Leistungsfähigkeit zieht aber auch Nachteile mit sich. Die Rückverfolgung ist häufig der wichtigste Faktor, der sich auf die Leistung des Moduls für reguläre Ausdrücke auswirkt. Der Entwickler kann jedoch steuern, wie sich das Modul für reguläre Ausdrücke verhält und wie die Rückverfolgung verwendet wird. In diesem Thema wird erläutert, wie die Rückverfolgung funktioniert und wie sie gesteuert werden kann.

HinweisHinweis

Bei einem NFA (Nondeterministic Finite Automaton)-Modul wie dem .NET Framework-Modul für reguläre Ausdrücke liegt die Verantwortung für die Erstellung effizienter und schneller regulärer Ausdrücke im Allgemeinen beim Entwickler.

Dieses Thema enthält folgende Abschnitte:

  • Linearer Vergleich ohne Rückverfolgung

  • Rückverfolgung mit optionalen Quantifizierern oder Alternierungskonstrukten

  • Rückverfolgung mit geschachtelten optionalen Quantifizierern

  • Steuern der Rückverfolgung

Linearer Vergleich ohne Rückverfolgung

Wenn das Muster eines regulären Ausdrucks nicht über optionale Quantifizierer oder Alternierungskonstrukte verfügt, wird das Modul für reguläre Ausdrücke zeitlich linear ausgeführt. Das heißt, nachdem das Modul für reguläre Ausdrücke dem ersten Sprachelement im Muster Text in der Eingabezeichenfolge zugeordnet hat, wird versucht, das nächste Sprachelement im Muster dem nächsten Zeichen oder der nächsten Zeichengruppe in der Eingabezeichenfolge zuzuordnen. Dies wird fortgesetzt, bis die Übereinstimmung erfolgreich ausgeführt wurde oder fehlschlägt. In beiden Fällen wechselt das Modul für reguläre Ausdrücke immer je ein Zeichen in der Eingabezeichenfolge weiter.

Dies wird im folgenden Beispiel veranschaulicht. Der reguläre Ausdruck e{2}\w\b sucht nach zwei Vorkommen des Buchstabens "e", gefolgt von einem beliebigen Wortzeichen, wiederum gefolgt von einer Wortgrenze.

Imports System.Text.RegularExpressions

Module Example
   Public Sub Main()
      Dim input As String = "needing a reed"
      Dim pattern As String = "e{2}\w\b"
      For Each match As Match In Regex.Matches(input, pattern)
         Console.WriteLine("{0} found at position {1}", _
                           match.Value, match.Index)
      Next   
   End Sub
End Module
' The example displays the following output:
'       eed found at position 11
using System;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      string input = "needing a reed";
      string pattern = @"e{2}\w\b";
      foreach (Match match in Regex.Matches(input, pattern))
         Console.WriteLine("{0} found at position {1}", 
                           match.Value, match.Index);
   }
}
// The example displays the following output:
//       eed found at position 11

Obwohl dieser reguläre Ausdruck den Quantifizierer {2} einschließt, wird er auf lineare Weise ausgewertet. Das Modul für reguläre Ausdrücke wird nicht zurückverfolgt, da {2} kein optionaler Quantifizierer ist, sondern eine genaue Zahl angibt und keine variable Anzahl von Übereinstimmungen des vorherigen Teilausdrucks. Daher versucht das Modul für reguläre Ausdrücke, eine Übereinstimmung des regulären Ausdrucksmusters mit der Eingabezeichenfolge wie in der folgenden Tabelle dargestellt zu finden.

Vorgang

Position im Muster

Position in der Zeichenfolge

Ergebnis

1

e

needing a reed (Index 0)

Keine Übereinstimmung.

2

e

eeding a reed (Index 1)

Mögliche Übereinstimmung.

3

e{2}

eding a reed (Index 2)

Mögliche Übereinstimmung.

4

\w

ding a reed (Index 3)

Mögliche Übereinstimmung.

5

\b

ing a reed (Index 4)

Mögliche Übereinstimmung schlägt fehl.

6

e

ing a reed (Index 5)

Keine Übereinstimmung.

7

e

ng a reed (Index 6)

Keine Übereinstimmung.

8

e

g a reed (Index 7)

Keine Übereinstimmung.

9

e

a reed (Index 8)

Keine Übereinstimmung.

10

e

a reed (Index 9)

Keine Übereinstimmung.

11

e

reed (Index 10)

Keine Übereinstimmung.

12

e

reed (Index 11)

Keine Übereinstimmung

13

e

eed (Index 12)

Mögliche Übereinstimmung.

14

e{2}

ed (Index 13)

Mögliche Übereinstimmung.

15

\w

d (Index 14)

Mögliche Übereinstimmung.

16

\b

(Index 15)

Übereinstimmung.

Wenn das Muster eines regulären Ausdrucks keine optionalen Quantifizierer oder Alternierungskonstrukte enthält, entspricht die maximale Anzahl von Vergleichen, die für die Übereinstimmung des regulären Ausdrucksmusters mit der Eingabezeichenfolge erforderlich sind, ungefähr der Anzahl der Zeichen in der Eingabezeichenfolge. Mit anderen Worten, das Modul für reguläre Ausdrücke wird zeitlich linear ausgeführt, wenn es keine optionalen Quantifizierer oder Alternierungskonstrukte enthält.

Zurück nach oben

Rückverfolgung mit optionalen Quantifizierern oder Alternierungskonstrukten

Wenn ein regulärer Ausdruck optionale Quantifizierer oder Alternierungskonstrukte enthält, erfolgt die Auswertung der Eingabezeichenfolge nicht mehr linear. Mustervergleiche mit einem NFA-Modul werden durch die Sprachelemente im regulären Ausdruck und nicht durch die Zeichen gesteuert, für die in der Eingabezeichenfolge Übereinstimmungen gefunden werden sollen. Daher versucht das Modul für reguläre Ausdrücke, vollständige Übereinstimmungen für die optionalen oder alternativen Teilausdrücke zu finden. Wenn zum nächsten Sprachelement im Teilausdruck gewechselt und keine Übereinstimmung gefunden wird, kann das Modul für reguläre Ausdrücke einen Teil der erfolgreichen Übereinstimmung aufgeben und zu einem zuvor gespeicherten Zustand zurückkehren, um eine Übereinstimmung des gesamten regulären Ausdrucks mit der Eingabezeichenfolge zu erzielen. Dieses Zurückkehren zu einem zuvor gespeicherten Zustand, um eine Übereinstimmung zu finden, wird als Rückverfolgung bezeichnet.

Als Beispiel dient das reguläre Ausdrucksmuster .*(es), das mit den Zeichen "es" und allen vorangestellten Zeichen übereinstimmt. Wenn die Eingabezeichenfolge "Essential services are provided by regular expressions." lautet, wird die gesamte Zeichenfolge bis einschließlich der Zeichen "es" im Wort "expressions" nach einer Übereinstimmung mit dem Muster durchsucht.

Imports System.Text.RegularExpressions

Module Example
   Public Sub Main()
      Dim input As String = "Essential services are provided by regular expressions."
      Dim pattern As String = ".*(es)" 
      Dim m As Match = Regex.Match(input, pattern, RegexOptions.IgnoreCase)
      If m.Success Then
         Console.WriteLine("'{0}' found at position {1}", _
                           m.Value, m.Index)
         Console.WriteLine("'es' found at position {0}", _
                           m.Groups(1).Index)                  
      End If     
   End Sub
End Module
'    'Essential services are provided by regular expres' found at position 0
'    'es' found at position 47
using System;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      string input = "Essential services are provided by regular expressions.";
      string pattern = ".*(es)"; 
      Match m = Regex.Match(input, pattern, RegexOptions.IgnoreCase);
      if (m.Success) {
         Console.WriteLine("'{0}' found at position {1}", 
                           m.Value, m.Index);
         Console.WriteLine("'es' found at position {0}", 
                           m.Groups[1].Index);      
      } 
   }
}
//    'Essential services are provided by regular expres' found at position 0
//    'es' found at position 47

Hierzu verwendet das Modul für reguläre Ausdrücke das Zurückverfolgen wie folgt:

  • Die gesamte Eingabezeichenfolge wird auf Übereinstimmung mit .* (Übereinstimmung mit keinem, einem oder mehreren Vorkommen beliebiger Zeichen) geprüft.

  • Es wird versucht, eine Übereinstimmung mit "e" im Muster des regulären Ausdrucks zu finden. Die Eingabezeichenfolge weist jedoch keine weiteren Zeichen für eine Übereinstimmung auf.

  • Es wird eine Rückverfolgung zur letzten erfolgreichen Übereinstimmung ausgeführt ("Essential services are provided by regular expressions") und versucht, eine Übereinstimmung von "e" mit dem Punkt am Satzende zu finden. Die Übereinstimmung schlägt fehl.

  • Die Rückverfolgung zu einer vorherigen erfolgreichen Übereinstimmung wird um je ein Zeichen fortgesetzt, bis die vorläufige übereinstimmende Teilzeichenfolge "Essential services are provided by regular expr" lautet. Anschließend wird das "e" im Muster mit dem zweiten "e" in "expressions" verglichen, und es wird eine Übereinstimmung gefunden.

  • Das "s" im Muster wird mit dem "s" verglichen, das dem übereinstimmenden Zeichen "e" folgt (das erste "s" in"expressions"). Die Übereinstimmung ist erfolgreich.

Bei einer Rückverfolgung erfordert das Abgleichen des regulären Ausdrucksmusters mit der Eingabezeichenfolge, die 55 Zeichen lang ist, 67 Vergleichsoperationen. Wenn das Muster des regulären Ausdrucks einen verzögerten Quantifizierer (*?(es)) enthält, sind für den Abgleich mit dem regulären Ausdruck interessanterweise weitere Vergleiche erforderlich. In diesem Fall muss keine Rückverfolgung vom Ende der Zeichenfolge bis zum "r" in "expressions" erfolgen, sondern das Modul für reguläre Ausdrücke würde eine Rückverfolgung bis zum Anfang der Zeichenfolge ausführen, um eine Übereinstimmung mit "Es" zu finden. Hierfür wären 113 Vergleiche erforderlich. Wenn das Muster eines regulären Ausdrucks ein einzelnes Alternierungskonstrukt oder einen einzelnen optionalen Quantifizierer enthält, ist die Anzahl der zum Abgleichen eines Musters erforderlichen Vergleichsoperationen im Allgemeinen mehr als doppelt so hoch wie die Anzahl der Zeichen in der Eingabezeichenfolge.

Zurück nach oben

Rückverfolgung mit geschachtelten optionalen Quantifizierern

Die Anzahl der für den Abgleich mit einem regulären Ausdrucksmuster erforderlichen Vergleichsoperationen kann sich exponentiell erhöhen, wenn das Muster viele Alternierungskonstrukte bzw. geschachtelte Alternierungskonstrukte oder, wie es am häufigsten vorkommt, geschachtelte optionale Quantifizierer enthält. Beispielsweise ist das reguläre Ausdrucksmuster ^(a+)+$ darauf ausgelegt, eine Übereinstimmung mit einer vollständigen Zeichenfolge zu finden, die mindestens ein "a" enthält. Das Beispiel stellt zwei Eingabezeichenfolgen mit identischer Länge bereit. Aber nur die erste Zeichenfolge stimmt mit dem Muster überein. Die System.Diagnostics.Stopwatch-Klasse wird verwendet, um zu bestimmen, wie lange die Vergleichsoperation dauert.

Imports System.Diagnostics
Imports System.Text.RegularExpressions

Module Example
   Public Sub Main()
      Dim pattern As String = "^(a+)+$"
      Dim inputs() As String = { "aaaaaa", "aaaaa!" }
      Dim rgx As New Regex(pattern)
      Dim sw As Stopwatch

      For Each input As String In inputs
         sw = Stopwatch.StartNew()   
         Dim match As Match = rgx.Match(input)
         sw.Stop()
         If match.Success Then
            Console.WriteLine("Matched {0} in {1}", match.Value, sw.Elapsed)
         Else
            Console.WriteLine("No match found in {0}", sw.Elapsed)
         End If      
      Next
   End Sub
End Module
using System;
using System.Diagnostics;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      string pattern = "^(a+)+$";
      string[] inputs = { "aaaaaa", "aaaaa!" };
      Regex rgx = new Regex(pattern);
      Stopwatch sw;

      foreach (string input in inputs) {
         sw = Stopwatch.StartNew();   
         Match match = rgx.Match(input);
         sw.Stop();
         if (match.Success)
            Console.WriteLine("Matched {0} in {1}", match.Value, sw.Elapsed);
         else
            Console.WriteLine("No match found in {0}", sw.Elapsed);
      }
   }
}

Wie die Ausgabe des Beispiels zeigt, brauchte das Modul für reguläre Ausdrücke zum Bestimmen, dass eine Eingabezeichenfolge nicht mit dem Muster übereinstimmt, etwa doppelt so lang wie für die Ermittlung einer übereinstimmenden Zeichenfolge. Dies liegt daran, dass eine fehlgeschlagene Übereinstimmung immer den ungünstigsten Fall darstellt. Das Modul für reguläre Ausdrücke muss den regulären Ausdruck verwenden, um allen möglichen Pfaden durch die Daten zu folgen, bevor es feststellen kann, ob die Übereinstimmung fehlschlägt. Durch die geschachtelten Klammern werden viele zusätzliche Pfade durch die Daten erstellt. Das Modul für reguläre Ausdrücke stellt fest, dass die zweite Zeichenfolge nicht mit dem Muster übereinstimmt, indem wie folgt vorgegangen wird:

  • Das Modul überprüft, ob es sich am Anfang der Zeichenfolge befindet, und vergleicht dann die ersten fünf Zeichen in der Zeichenfolge mit dem Muster a+. Anschließend wird sichergestellt, dass keine weiteren Gruppen des Zeichens "a" in der Zeichenfolge vorhanden sind. Schließlich wird das Ende der Zeichenfolge überprüft. Da ein zusätzliches Zeichen in der Zeichenfolge verbleibt, schlägt die Übereinstimmung fehl. Diese fehlgeschlagene Suche nach Übereinstimmung erfordert 9 Vergleiche. Das Modul für reguläre Ausdrücke speichert darüber hinaus Zustandsinformationen aus den Übereinstimmungen von "a" (hier bezeichnet als Übereinstimmung 1), "aa" (Übereinstimmung 2), "aaa" (Übereinstimmung 3) und "aaaa" (Übereinstimmung 4).

  • Das Modul kehrt zur zuvor gespeicherten Übereinstimmung 4 zurück. Es wird ermittelt, dass ein zusätzliches Zeichen "a" vorhanden ist, das einer zusätzlichen Erfassungsgruppe zugewiesen werden soll. Schließlich wird das Ende der Zeichenfolge überprüft. Da ein zusätzliches Zeichen in der Zeichenfolge verbleibt, schlägt die Übereinstimmung fehl. Diese fehlgeschlagene Suche nach Übereinstimmung erfordert 4 Vergleiche. Bisher wurden insgesamt 13 Vergleiche ausgeführt.

  • Das Modul kehrt zur zuvor gespeicherten Übereinstimmung 3 zurück. Es wird ermittelt, dass zwei zusätzliche "a"-Zeichen vorhanden sind, die einer zusätzlichen Erfassungsgruppe zugewiesen werden sollen. Allerdings schlägt die Überprüfung des Zeichenfolgenendes fehl. Anschließend kehrt das Modul zur Übereinstimmung 3 zurück und versucht, die zwei zusätzlichen "a"-Zeichen in zwei zusätzlichen Erfassungsgruppen abzugleichen. Die Überprüfung des Zeichenfolgenendes schlägt weiterhin fehl. Diese fehlgeschlagenen Übereinstimmungen erfordern 12 Vergleiche. Bisher wurden insgesamt 25 Vergleiche ausgeführt.

Der Vergleich der Eingabezeichenfolge mit dem regulären Ausdruck wird auf diese Weise fortgesetzt, bis das Modul für reguläre Ausdrücke alle möglichen Übereinstimmungskombinationen durchlaufen hat und dann feststellt, dass keine Übereinstimmung vorhanden ist. Aufgrund der geschachtelten Quantifizierer handelt es sich bei diesem Verweis um O(2n) oder einen exponentiellen Vorgang, wobei n für die Anzahl der Zeichen in der Eingabezeichenfolge steht. Dies bedeutet, dass im ungünstigsten Fall für eine Eingabezeichenfolge von 30 Zeichen etwa 1.073.741.824 Vergleiche und für eine Eingabezeichenfolge von 40 Zeichen ungefähr 1.099.511.627.776 Vergleiche erforderlich sind. Wenn Sie Zeichenfolgen mit dieser oder sogar einer größeren Länge verwenden, kann die Ausführung von Methoden mit regulären Ausdrücken erhebliche Zeit in Anspruch nehmen, wenn diese Eingaben verarbeiten, die nicht mit dem regulären Ausdrucksmuster übereinstimmen.

Zurück nach oben

Steuern der Rückverfolgung

Mithilfe der Rückverfolgung können Sie leistungsstarke, flexible reguläre Ausdrücke erstellen. Wie allerdings im vorangegangenen Abschnitt erläutert, sind diese Vorteile u. U. mit einer inakzeptabel schlechten Leistung verknüpft. .NET Framework unterstützt drei Sprachelemente für reguläre Ausdrücke, die das Zurückverfolgen einschränken oder unterdrücken und komplexe reguläre Ausdrücke bei nur wenigen oder gar keinen Leistungseinbußen unterstützen: nicht zurückverfolgende Teilausdrücke, Lookbehindassertionen und Lookaheadassertionen. Weitere Informationen zu den einzelnen Sprachelementen finden Sie unter Gruppierungskonstrukte.

Nicht zurückverfolgender Teilausdruck

Das Sprachelement (?> Teilausdruck) unterdrückt die Rückverfolgung in einem Teilausdruck. Das Element ist nützlich, um die mit fehlgeschlagenen Übereinstimmungen zusammenhängenden Leistungsprobleme zu vermeiden.

Das folgende Beispiel zeigt, wie das Unterdrücken der Rückverfolgung bei Verwendung von geschachtelten Quantifizierern die Leistung verbessert. Es wird gemessen, wie viel Zeit das Modul für reguläre Ausdrücke benötigt, um zu ermitteln, dass eine Eingabezeichenfolge nicht mit zwei regulären Ausdrücken übereinstimmt. Der erste reguläre Ausdruck verwendet die Rückverfolgung, um eine Übereinstimmung mit einer Zeichenfolge zu finden, in der Folgendes ein Mal oder mehrmals vorkommt: eine oder mehrere hexadezimale Ziffern, gefolgt von einem Doppelpunkt, gefolgt von einer oder mehreren hexadezimalen Ziffern, gefolgt von zwei Doppelpunkten. Der zweite reguläre Ausdruck ist mit dem ersten identisch, mit der Ausnahme, dass dieser die Rückverfolgung deaktiviert. Wie die Ausgabe im Beispiel zeigt, ist die Leistungsverbesserung durch das Deaktivieren der Rückverfolgung signifikant.

Imports System.Diagnostics
Imports System.Text.RegularExpressions

Module Example
   Public Sub Main()
      Dim input As String = "b51:4:1DB:9EE1:5:27d60:f44:D4:cd:E:5:0A5:4a:D24:41Ad:"
      Dim matched As Boolean
      Dim sw As Stopwatch

      Console.WriteLine("With backtracking:")
      Dim backPattern As String = "^(([0-9a-fA-F]{1,4}:)*([0-9a-fA-F]{1,4}))*(::)$"
      sw = Stopwatch.StartNew()
      matched = Regex.IsMatch(input, backPattern)
      sw.Stop()
      Console.WriteLine("Match: {0} in {1}", Regex.IsMatch(input, backPattern), sw.Elapsed)
      Console.WriteLine()

      Console.WriteLine("Without backtracking:")
      Dim noBackPattern As String = "^((?>[0-9a-fA-F]{1,4}:)*(?>[0-9a-fA-F]{1,4}))*(::)$"
      sw = Stopwatch.StartNew()
      matched = Regex.IsMatch(input, noBackPattern)
      sw.Stop()
      Console.WriteLine("Match: {0} in {1}", Regex.IsMatch(input, noBackPattern), sw.Elapsed)
   End Sub
End Module
' The example displays the following output:
'       With backtracking:
'       Match: False in 00:00:27.4282019
'       
'       Without backtracking:
'       Match: False in 00:00:00.0001391
using System;
using System.Diagnostics;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      string input = "b51:4:1DB:9EE1:5:27d60:f44:D4:cd:E:5:0A5:4a:D24:41Ad:";
      bool matched;
      Stopwatch sw;

      Console.WriteLine("With backtracking:");
      string backPattern = "^(([0-9a-fA-F]{1,4}:)*([0-9a-fA-F]{1,4}))*(::)$";
      sw = Stopwatch.StartNew();
      matched = Regex.IsMatch(input, backPattern);
      sw.Stop();
      Console.WriteLine("Match: {0} in {1}", Regex.IsMatch(input, backPattern), sw.Elapsed);
      Console.WriteLine();

      Console.WriteLine("Without backtracking:");
      string noBackPattern = "^((?>[0-9a-fA-F]{1,4}:)*(?>[0-9a-fA-F]{1,4}))*(::)$";
      sw = Stopwatch.StartNew();
      matched = Regex.IsMatch(input, noBackPattern);
      sw.Stop();
      Console.WriteLine("Match: {0} in {1}", Regex.IsMatch(input, noBackPattern), sw.Elapsed);
   }
}
// The example displays output like the following:
//       With backtracking:
//       Match: False in 00:00:27.4282019
//       
//       Without backtracking:
//       Match: False in 00:00:00.0001391

Lookbehindassertionen

.NET Framework enthält zwei Sprachelemente ((?<=Teilausdruck) und (?<!Teilausdruck)), die mit dem bzw. den vorherigen Zeichen in der Eingabezeichenfolge übereinstimmen. Beide Sprachelemente sind Assertionen mit einer Breite von 0. Das heißt, sie bestimmen ohne Vorlaufen oder Rückverfolgung, ob eine Übereinstimmung des oder der Zeichen unmittelbar vor dem aktuellen Zeichen mit dem Teilausdruck vorliegt.

(?<=Teilausdruck) ist eine positive Lookbehindassertion. Das heißt, das oder die Zeichen vor der aktuellen Position muss bzw. müssen mit dem Teilausdruck übereinstimmen. (?<!Teilausdruck) ist eine negative Lookbehindassertion. Das heißt, es darf keine Übereinstimmung des oder der Zeichen vor der aktuellen Position mit dem Teilausdruck vorliegen. Positive und negative Lookbehindassertionen sind besonders hilfreich, wenn der Teilausdruck eine Teilmenge des vorherigen Teilausdrucks ist.

Im folgenden Beispiel werden zwei äquivalente reguläre Ausdrucksmuster verwendet, die den Benutzernamen in einer E-Mail-Adresse überprüfen. Aufgrund übermäßiger Rückverfolgung tritt beim ersten Muster eine schlechte Leistung auf. Das zweite Muster ist eine Änderung des ersten regulären Ausdrucks, indem ein geschachtelter Quantifizierer durch eine positive Lookbehindassertion ersetzt wird. In der Beispielausgabe wird die Ausführungszeit der Regex.IsMatch-Methode angezeigt.

Module Example
   Public Sub Main()
      Dim sw As Stopwatch
      Dim input As String = "aaaaaaaaaaaaaaaaaaaa"
      Dim result As Boolean

      Dim pattern As String = "^[0-9A-Z]([-.\w]*[0-9A-Z])?@"
      sw = Stopwatch.StartNew()
      result = Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase)
      sw.Stop()
      Console.WriteLine("Match: {0} in {1}", result, sw.Elapsed)

      Dim behindPattern As String = "^[0-9A-Z][-.\w]*(?<=[0-9A-Z])@"
      sw = Stopwatch.StartNew()
      result = Regex.IsMatch(input, behindPattern, RegexOptions.IgnoreCase)
      sw.Stop()
      Console.WriteLine("Match with Lookbehind: {0} in {1}", result, sw.Elapsed)
   End Sub
End Module
' The example displays the following output:
'       Match: True in 00:00:00.0017549
'       Match with Lookbehind: True in 00:00:00.0000659
using System;
using System.Diagnostics;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      Stopwatch sw;
      string input = "aaaaaaaaaaaaaaaaaaaa";
      bool result;

      string pattern = @"^[0-9A-Z]([-.\w]*[0-9A-Z])?@";
      sw = Stopwatch.StartNew();
      result = Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase);
      sw.Stop();
      Console.WriteLine("Match: {0} in {1}", result, sw.Elapsed);

      string behindPattern = @"^[0-9A-Z][-.\w]*(?<=[0-9A-Z])@";
      sw = Stopwatch.StartNew();
      result = Regex.IsMatch(input, behindPattern, RegexOptions.IgnoreCase);
      sw.Stop();
      Console.WriteLine("Match with Lookbehind: {0} in {1}", result, sw.Elapsed);
   }
}
// The example displays the following output:
//       Match: True in 00:00:00.0017549
//       Match with Lookbehind: True in 00:00:00.0000659

Das erste Muster für reguläre Ausdrücke ^[0-9A-Z]([-.\w]*[0-9A-Z])*@ wird entsprechend der folgenden Tabelle definiert.

Muster

Beschreibung

^

Die Suche nach Übereinstimmungen soll am Anfang der Zeichenfolge beginnen.

[0-9A-Z]

Übereinstimmung mit einem alphanumerischen Zeichen. Bei diesem Vergleich wird die Groß-/Kleinschreibung nicht beachtet, da die Regex.IsMatch-Methode mit der RegexOptions.IgnoreCase-Option aufgerufen wird.

[-. \w]*

Übereinstimmung mit keinem, einem oder mehreren Vorkommen eines Bindestrichs, eines Punkts oder eines Wortzeichens.

[0-9A-Z]

Übereinstimmung mit einem alphanumerischen Zeichen.

([-. \w]*[0-9A-Z])*

Übereinstimmung mit keinem oder mehreren Vorkommen der Kombination aus keinem oder mehreren Bindestrichen, Punkten oder Wortzeichen, gefolgt von einem alphanumerischen Zeichen. Dies ist die erste Erfassungsgruppe.

@

Übereinstimmung mit einem @-Zeichen.

Das zweite Muster für reguläre Ausdrücke ^[0-9A-Z][-.\w]*(?<=[0-9A-Z])@ verwendet eine positive Lookbehindassertion. Das Muster wird wie in der folgenden Tabelle gezeigt definiert.

Muster

Beschreibung

^

Die Suche nach Übereinstimmungen soll am Anfang der Zeichenfolge beginnen.

[0-9A-Z]

Übereinstimmung mit einem alphanumerischen Zeichen. Bei diesem Vergleich wird die Groß-/Kleinschreibung nicht beachtet, da die Regex.IsMatch-Methode mit der RegexOptions.IgnoreCase-Option aufgerufen wird.

[-. \w]*

Übereinstimmung mit keinem oder mehreren Vorkommen eines Bindestrichs, eines Punkts oder eines Wortzeichens.

(?<=[0-9A-Z])

Überprüfung des letzten übereinstimmenden Zeichens und Fortsetzen des Abgleichs, wenn es sich um ein alphanumerisches Zeichen handelt. Beachten Sie, dass alphanumerische Zeichen eine Teilmenge des Satzes sind, der aus Punkten, Bindestrichen und allen Wortzeichen besteht.

@

Übereinstimmung mit einem @-Zeichen.

Lookaheadassertionen

.NET Framework enthält zwei Sprachelemente ((?=Teilausdruck) und (?!Teilausdruck)), die mit dem bzw. den nächsten Zeichen in der Eingabezeichenfolge übereinstimmen. Beide Sprachelemente sind Assertionen mit einer Breite von 0. Das heißt, sie bestimmen ohne Vorlaufen oder Rückverfolgung, ob eine Übereinstimmung des oder der Zeichen unmittelbar nach dem aktuellen Zeichen mit dem Teilausdruck vorliegt.

(?=Teilausdruck) ist eine positive Lookaheadassertion. Das heißt, das oder die Zeichen nach der aktuellen Position muss bzw. müssen mit dem Teilausdruck übereinstimmen. (?!Teilausdruck) ist eine negative Lookaheadassertion. Das heißt, es darf keine Übereinstimmung des oder der Zeichen nach der aktuellen Position mit dem Teilausdruck vorliegen. Positive und negative Lookaheadassertionen sind besonders hilfreich, wenn der Teilausdruck eine Teilmenge des nächsten Teilausdrucks ist.

Im folgenden Beispiel werden zwei äquivalente Muster für reguläre Ausdrücke verwendet, die einen vollqualifizierten Typnamen überprüfen. Aufgrund übermäßiger Rückverfolgung tritt beim ersten Muster eine schlechte Leistung auf. Das zweite Muster ist eine Änderung des ersten regulären Ausdrucks, indem ein geschachtelter Quantifizierer durch eine positive Lookaheadassertion ersetzt wird. In der Beispielausgabe wird die Ausführungszeit der Regex.IsMatch-Methode angezeigt.

Imports System.Diagnostics
Imports System.Text.RegularExpressions

Module Example
   Public Sub Main()
      Dim input As String = "aaaaaaaaaaaaaaaaaaaaaa."
      Dim result As Boolean
      Dim sw As Stopwatch

      Dim pattern As String = "^(([A-Z]\w*)+\.)*[A-Z]\w*$"
      sw = Stopwatch.StartNew()
      result = Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase)
      sw.Stop()
      Console.WriteLine("{0} in {1}", result, sw.Elapsed)

      Dim aheadPattern As String = "^((?=[A-Z])\w+\.)*[A-Z]\w*$"
      sw = Stopwatch.StartNew()
      result = Regex.IsMatch(input, aheadPattern, RegexOptions.IgnoreCase)
      sw.Stop()
      Console.WriteLine("{0} in {1}", result, sw.Elapsed)
   End Sub
End Module
' The example displays the following output:
'       False in 00:00:03.8003793
'       False in 00:00:00.0000866
using System;
using System.Diagnostics;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      string input = "aaaaaaaaaaaaaaaaaaaaaa.";
      bool result;
      Stopwatch sw;

      string pattern = @"^(([A-Z]\w*)+\.)*[A-Z]\w*$";
      sw = Stopwatch.StartNew();
      result = Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase);
      sw.Stop();
      Console.WriteLine("{0} in {1}", result, sw.Elapsed);

      string aheadPattern = @"^((?=[A-Z])\w+\.)*[A-Z]\w*$";
      sw = Stopwatch.StartNew();
      result = Regex.IsMatch(input, aheadPattern, RegexOptions.IgnoreCase);
      sw.Stop();
      Console.WriteLine("{0} in {1}", result, sw.Elapsed);
   }
}
// The example displays the following output:
//       False in 00:00:03.8003793
//       False in 00:00:00.0000866

Das erste Muster für reguläre Ausdrücke ^(([A-Z]\w*)+\.)*[A-Z]\w*$ wird entsprechend der folgenden Tabelle definiert.

Muster

Beschreibung

^

Die Suche nach Übereinstimmungen soll am Anfang der Zeichenfolge beginnen.

([A-Z]\w*)+\.

Übereinstimmung mit einem Buchstaben (A-Z), gefolgt von keinem oder mehreren Wortzeichen (einmaliges oder mehrmaliges Vorkommen), gefolgt von einem Punkt. Bei diesem Vergleich wird die Groß-/Kleinschreibung nicht beachtet, da die Regex.IsMatch-Methode mit der RegexOptions.IgnoreCase-Option aufgerufen wird.

(([A-Z]\w*)+\.)*

Keine oder mehrmalige Übereinstimmung mit dem vorherigen Muster.

[A-Z]\w*

Übereinstimmung mit einem Buchstaben, gefolgt von keinem oder mehreren Wortzeichen.

$

Ende des Abgleichs am Ende der Eingabezeichenfolge.

Das zweite Muster für reguläre Ausdrücke ^((?=[A-Z])\w+\.)*[A-Z]\w*$ verwendet eine positive Lookaheadassertion. Das Muster wird wie in der folgenden Tabelle gezeigt definiert.

Muster

Beschreibung

^

Die Suche nach Übereinstimmungen soll am Anfang der Zeichenfolge beginnen.

(?=[A-Z])

Lookahead zum ersten Zeichen und die Suche nach Übereinstimmungen fortsetzen, wenn es sich um einen Buchstaben (A-Z) handelt. Bei diesem Vergleich wird die Groß-/Kleinschreibung nicht beachtet, da die Regex.IsMatch-Methode mit der RegexOptions.IgnoreCase-Option aufgerufen wird.

\w+\.

Übereinstimmung mit einem oder mehreren Wortzeichen, gefolgt von einem Punkt.

((?=[A-Z])\w+\.)*

Übereinstimmung mit dem Muster aus einem oder mehreren Wortzeichen, gefolgt von keinem oder mehreren Vorkommen eines Punkts. Das erste Wortzeichen muss ein Buchstabe sein.

[A-Z]\w*

Übereinstimmung mit einem Buchstaben, gefolgt von keinem oder mehreren Wortzeichen.

$

Ende des Abgleichs am Ende der Eingabezeichenfolge.

Zurück nach oben

Siehe auch

Referenz

Quantifizierer

Alternierungskonstrukte

Gruppierungskonstrukte

Konzepte

Reguläre Ausdrücke von .NET Framework

Sprachelemente für reguläre Ausdrücke

Weitere Ressourcen

Empfohlene Vorgehensweisen für die Verwendung von regulären Ausdrücken in .NET Framework