Operazioni stringa: ricerca basata su criteri di ricerca basata su intervalli, prestazioni e criteri di ricerca

Questo articolo illustra tre operazioni di stringa: criteri di espressione regolare corrispondenti a System.Text.RegularExpressions.Regex, ricerca senza allocazione su ReadOnlySpan<T>e scelta di un StringComparison valore per confronti rapidi e corretti.

Trovare testo specifico usando espressioni regolari

La System.Text.RegularExpressions.Regex classe cerca nelle stringhe i criteri anziché le sottostringhe fisse. Il metodo statico Regex.IsMatch accetta la stringa di input, un criterio e i flag facoltativi RegexOptions .

Nell'esempio seguente ogni frase cerca la parola o larelativa senza distinzione tra maiuscole e minuscole. Il criterio the(ir)?\s corrisponde the facoltativamente seguito da ir, quindi un carattere di spazio vuoto:

Modello Meaning
the corrisponde al testo letterale the
(ir)? corrispondenza 0 o 1 occorrenza di ir
\s corrisponde a un carattere di spazio vuoto
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();
    }
}

Convalidare le stringhe in base a un modello

Per verificare se un intero input corrisponde a una forma, ancorare il motivo con ^ e $. L'esempio seguente convalida che ogni stringa sia un numero di telefono in stile USA: tre cifre, tre cifre, quattro cifre, separate da trattini:

Modello Meaning
^ corrisponde all'inizio della stringa
\d{3} corrisponde esattamente a tre cifre
- corrisponde a un carattere letterale -
\d{4} corrisponde esattamente a quattro cifre
$ trovare la corrispondenza con la fine della stringa
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");
}

Per la sintassi completa dei criteri, vedere Linguaggio di espressioni regolari - Riferimento rapido.

Scegliere tra string metodi ed espressioni regolari

string metodi e Regex risolvere problemi sovrapposti. Preferisce string i metodi quando il testo che si sta cercando è un valore letterale, un prefisso noto o un suffisso o un delimitatore fisso. Sono più semplici da leggere e velocizzare, perché non pagano il costo della compilazione e dell'esecuzione di un modello. Regex Raggiungere quando la destinazione di ricerca è una forma, ad esempio alternanze, gruppi facoltativi, classi di caratteri ripetute o convalida ancorata. Come regola generale, se è possibile scrivere la ricerca come una o due string.Contains / / StartsWithIndexOf chiamate, farlo.

Eseguire ricerche con ReadOnlySpan<char>

Quando si analizzano input di grandi dimensioni o si esegue una ricerca in un percorso critico, le allocazioni per chiamata di string.Substring e string.Split possono dominare. ReadOnlySpan<char> offre una visualizzazione su una stringa esistente (o matrice o buffer dello stack) senza copiare e MemoryExtensions fornisce equivalenti basati su span dei metodi comuni string , tra cui 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

La ricerca basata su span evita le allocazioni perché le sezioni (input[start..], rest[..end]) sono semplicemente finestre sui caratteri originali. Lo stesso approccio si adatta all'analisi di elenchi chiave-valore, intestazioni e altro testo delimitato senza chiamare Substringmai .

Considerazioni sulle prestazioni per StringComparison

La maggior parte dei string metodi di istanza include overload che accettano un StringComparison valore. Metodi come String.Equals(String) l'impostazione predefinita ordinale, ma String.Compare(String, String) per String.IndexOf(String) impostazione predefinita sono le impostazioni cultura correnti. Questa differenza è importante in due modi:

  • Velocità. Il confronto ordinale è un test di byte per byte eseguito in cicli ristretti e vettorializzati. Il confronto compatibile con le impostazioni cultura consulta una tabella di ordinamento, illustra la combinazione di caratteri e applica regole specifiche delle impostazioni locali. Per lo stesso input, può essere un ordine di grandezza più lento.
  • Correttezza. Il confronto con riconoscimento delle impostazioni cultura può piegare i caratteri che non ci si aspetta (turco, tedesco iß/Ia ss, legature). Questo comportamento è adatto per l'ordinamento dei nomi che un utente vede, ma non è corretto per l'analisi di identificatori, percorsi o token di protocollo.

Per il testo definito dal computer, ad esempio nomi di file, URL, intestazioni HTTP, identificatori e chiavi di configurazione, passare StringComparison.Ordinal o StringComparison.OrdinalIgnoreCase in modo esplicito. Riservare valori con riconoscimento delle impostazioni cultura per il testo in linguaggio naturale visualizzato agli utenti. Per indicazioni complete, vedere procedure Best per confrontare le stringhe in .NET.

Vedere anche