Tekenreeksbewerkingen: Patroonkoppeling, prestaties en zoekopdrachten op basis van span

In dit artikel worden drie tekenreeksbewerkingen behandeld: patroon met reguliere expressies die overeenkomen met System.Text.RegularExpressions.Regexde toewijzingsvrije zoekopdracht ReadOnlySpan<T>en het kiezen van een StringComparison waarde voor juiste, snelle vergelijkingen.

Specifieke tekst zoeken met behulp van reguliere expressies

De System.Text.RegularExpressions.Regex klasse zoekt tekenreeksen naar patronen in plaats van vaste subtekenreeksen. De statische Regex.IsMatch methode gebruikt de invoertekenreeks, een patroon en optionele RegexOptions vlaggen.

In het volgende voorbeeld wordt elke zin doorzocht naar het woord ofde bijbehorende, niet hoofdlettergevoelig. Het patroon the(ir)?\s komt the optioneel gevolgd door iren vervolgens een witruimteteken:

Patroon Meaning
the overeenkomen met de letterlijke tekst the
(ir)? overeenkomen met 0 of 1 exemplaar van ir
\s overeenkomen met een spatieteken
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();
    }
}

Tekenreeksen valideren op basis van een patroon

Als u wilt controleren of een volledige invoer overeenkomt met een shape, ankert u het patroon met ^ en $. In het volgende voorbeeld wordt gevalideerd dat elke tekenreeks een amerikaans telefoonnummer is: drie cijfers, drie cijfers, vier cijfers, gescheiden door streepjes:

Patroon Meaning
^ overeenkomen met het begin van de tekenreeks
\d{3} exact drie cijfers bevatten
- een letterlijk - teken laten overeenkomen
\d{4} exact vier cijferige tekens afstemmen
$ overeenkomen met het einde van de tekenreeks
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");
}

Zie Voor de volledige patroonsyntaxis de reguliere expressietaal - snelzoekgids.

Kiezen tussen string methoden en reguliere expressies

string methoden en Regex overlappende problemen oplossen. Geef de voorkeur string aan methoden wanneer de tekst die u zoekt een letterlijke waarde, een bekend voor- of achtervoegsel of een vast scheidingsteken is. Ze zijn eenvoudiger te lezen en sneller, omdat ze niet de kosten betalen voor het compileren en uitvoeren van een patroon. Bereik wanneer Regex het zoekdoel een vorm is, zoals alternations, optionele groepen, herhaalde tekenklassen of verankerde validatie. Als u de zoekopdracht als vuistregel kunt schrijven als een of twee string.Contains / / StartsWithIndexOf aanroepen, doet u dit.

Zoeken met ReadOnlySpan<char>

Wanneer u grote invoer parseert of een zoekopdracht uitvoert op een dynamisch pad, kunnen de toewijzingen per aanroep van string.Substring en string.Split kunnen ze overheersten. ReadOnlySpan<char> geeft u een weergave van een bestaande tekenreeks (of matrix of stackbuffer) zonder te kopiëren en MemoryExtensions biedt op span gebaseerde equivalenten van de algemene string methoden, waaronder 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

Zoeken op basis van span voorkomt toewijzingen omdat de segmenten (input[start..], rest[..end]) gewoon vensters zijn van de oorspronkelijke tekens. Dezelfde methode wordt geschaald om sleutel-waardelijsten, kopteksten en andere tekst met scheidingstekens te parseren zonder ooit aan te roepen Substring.

Prestatieoverwegingen voor StringComparison

De meeste string exemplaarmethoden hebben overbelastingen die een StringComparison waarde accepteren. Methoden zoals String.Equals(String) de standaardinstelling voor rangtelwoorden, maar String.Compare(String, String) ook de String.IndexOf(String)huidige cultuur. Dit verschil is op twee manieren belangrijk:

  • Snelheid. Ordinale vergelijking is een byte-for-bytetest die wordt uitgevoerd in strakke, vectorized lussen. Cultuurbewuste vergelijking raadpleegt een sorteertabel, begeleidt het combineren van tekens en past landinstellingenspecifieke regels toe. Voor dezelfde invoer kan het een orde van grootte langzamer zijn.
  • Juistheid. Cultuurbewuste vergelijking kan tekens vouwen die u niet verwacht (Turks i/I, Duits ß tot ss, ligaturen). Dit gedrag is geschikt voor het sorteren van namen die een gebruiker ziet, maar onjuist voor het parseren van id's, paden of protocoltokens.

Voor door de machine gedefinieerde tekst, zoals bestandsnamen, URL's, HTTP-headers, id's en configuratiesleutels, geeft u door StringComparison.Ordinal of StringComparison.OrdinalIgnoreCase expliciet. Reserveer cultuurbewuste waarden voor tekst in natuurlijke taal die voor gebruikers wordt weergegeven. Zie Best-procedures voor het vergelijken van tekenreeksen in .NET voor uitgebreide richtlijnen.

Zie ook