Zeichenfolgenvorgänge: Musterabgleich, Leistung und spanbasierte Suche

In diesem Artikel werden drei Zeichenfolgenvorgänge behandelt: Musterabgleich mit regulärem Ausdruck mit System.Text.RegularExpressions.Regexzuordnungsfreien Suchvorgängen ReadOnlySpan<T>und Auswählen eines StringComparison Werts für korrekte, schnelle Vergleiche.

Suchen nach bestimmtem Text mithilfe regulärer Ausdrücke

Die System.Text.RegularExpressions.Regex Klasse durchsucht Zeichenfolgen nach Mustern und nicht nach festen Teilzeichenfolgen. Die statische Regex.IsMatch Methode verwendet die Eingabezeichenfolge, ein Muster und optionale RegexOptions Flags.

Im folgenden Beispiel wird jeder Satz nach dem Wort durchsucht,wobei die Groß-/Kleinschreibung nicht beachtet wird. Das Muster the(ir)?\s entspricht the optional gefolgt von ir, dann ein Leerzeichen:

Muster Bedeutung
the entspricht dem Literaltext the
(ir)? Übereinstimmung mit 0 oder 1 Vorkommen von ir
\s Übereinstimmung mit einem Leerzeichen
string[] sentences =
[
    "Put the water over there.",
    "They're quite thirsty.",
    "Their water bottles broke."
];

string pattern = @"the(ir)?\s";

foreach (string s in sentences)
{
    Console.Write($"{s,28}");

    if (Regex.IsMatch(s, pattern, RegexOptions.IgnoreCase))
    {
        Console.WriteLine($"  (match for '{pattern}' found)");
    }
    else
    {
        Console.WriteLine();
    }
}

Überprüfen von Zeichenfolgen anhand eines Musters

Um zu überprüfen, ob eine gesamte Eingabe mit einem Shape übereinstimmt, verankern Sie das Muster mit ^ und $. Im folgenden Beispiel wird überprüft, ob jede Zeichenfolge eine Telefonnummer im US-Stil ist: drei Ziffern, drei Ziffern, vier Ziffern, durch Bindestriche getrennt:

Muster Bedeutung
^ entspricht dem Anfang der Zeichenfolge
\d{3} Exakt dreistellige Zeichen entsprechen
- Übereinstimmung mit einem Literalzeichen -
\d{4} Exakt vierstellige Zeichen entsprechen
$ mit dem Ende der Zeichenfolge übereinstimmen
string[] numbers =
[
    "123-555-0190",
    "444-234-22450",
    "690-555-0178",
    "146-893-232",
    "146-555-0122",
    "4007-555-0111",
    "407-555-0111",
    "407-2-5555",
    "407-555-8974",
    "407-2ab-5555",
    "690-555-8148",
    "146-893-232-"
];

string pattern = """^\d{3}-\d{3}-\d{4}$""";

foreach (string s in numbers)
{
    Console.Write($"{s,14}");
    Console.WriteLine(Regex.IsMatch(s, pattern) ? " - valid" : " - invalid");
}

Die vollständige Mustersyntax finden Sie in der Sprache für reguläre Ausdrücke – Kurzübersicht.

Auswählen zwischen string Methoden und regulären Ausdrücken

string Methoden und Regex Lösen überlappender Probleme. Bevorzugen Sie string Methoden, wenn der gesuchte Text ein Literalwert, ein bekanntes Präfix oder Suffix oder ein festes Trennzeichen ist. Sie sind einfacher zu lesen und schneller, da sie nicht die Kosten für das Kompilieren und Ausführen eines Musters bezahlen. Regex Erreichen Sie, wann das Suchziel ein Shape ist, z. B. Alternationen, optionale Gruppen, wiederholte Zeichenklassen oder verankerte Überprüfung. Wenn Sie die Suche als eine oder zwei string.Contains / / StartsWithIndexOf Aufrufe schreiben können, führen Sie dies als Faustregel aus.

Suchen mithilfe von ReadOnlySpan<char>

Wenn Sie große Eingaben analysieren oder eine Suche auf einem heißen Pfad ausführen, können die Zuordnungen string.Substring pro Anruf dominiert werden.string.Split ReadOnlySpan<char> bietet Eine Ansicht über eine vorhandene Zeichenfolge (oder ein Array oder Stapelpuffer) ohne Kopieren und MemoryExtensions stellt span-basierte Entsprechungen der allgemeinen string Methoden bereit, einschließlich IndexOf:

ReadOnlySpan<char> input = "key1=alpha;key2=beta;key3=gamma".AsSpan();
ReadOnlySpan<char> needle = "key2=".AsSpan();

int start = input.IndexOf(needle);
if (start >= 0)
{
    ReadOnlySpan<char> rest = input[(start + needle.Length)..];
    int end = rest.IndexOf(';');
    ReadOnlySpan<char> value = end >= 0 ? rest[..end] : rest;
    Console.WriteLine($"key2 = {value}");
}
// => key2 = beta

Bei der span-basierten Suche werden Zuordnungen vermieden, da die Segmente (input[start..], rest[..end]) einfach über die ursprünglichen Zeichen stehen. Derselbe Ansatz wird auf die Analyse von Schlüsselwertlisten, Kopfzeilen und anderen durch Trennzeichen getrennten Text skaliert, ohne jemals aufrufen zu Substringmüssen.

Leistungsüberlegungen für StringComparison

Die meisten string Instanzenmethoden weisen Überladungen auf, die einen StringComparison Wert akzeptieren. Methoden wie Standardeinstellung String.Equals(String) für Ordnungszahlen, aber String.Compare(String, String) als String.IndexOf(String) Standard für die aktuelle Kultur. Dieser Unterschied ist auf zwei Arten von Bedeutung:

  • Geschwindigkeit. Der Ordinalvergleich ist ein Byte-for-Byte-Test, der in engen, vektorisierten Schleifen ausgeführt wird. Der kulturbezogene Vergleich konsultiert eine Sortiertabelle, führt Durchgänge zum Kombinieren von Zeichen und wendet gebietsschemaspezifische Regeln an. Für dieselbe Eingabe kann es sich um eine Größenordnung langsamer sein.
  • Richtigkeit. Kulturbewusster Vergleich kann Zeichen falten, die Sie nicht erwarten (Türkisch i/I, Deutsch ß bis ssLigaturen). Dieses Verhalten eignet sich zum Sortieren von Namen, die ein Benutzer sieht, aber falsch für die Analyse von Bezeichnern, Pfaden oder Protokolltoken.

Für computerdefinierter Text, z. B. Dateinamen, URLs, HTTP-Header, Bezeichner und Konfigurationsschlüssel, übergeben StringComparison.Ordinal oder StringComparison.OrdinalIgnoreCase explizit. Reservieren Sie kulturbewusste Werte für Text in natürlicher Sprache, die Benutzern angezeigt werden. Umfassende Anleitungen finden Sie unter Best-Methoden zum Vergleichen von Zeichenfolgen in .NET.

Siehe auch