Esempio di espressione regolare: Ricerca di HREF

Nell'esempio riportato di seguito viene cercata una stringa di input e vengono visualizzati tutti i valori href="…" e le relative posizioni nella stringa.

Avviso

Quando si utilizza System.Text.RegularExpressions per elaborare input non attendibili, passare un timeout. Un utente malintenzionato può fornire input a RegularExpressions, provocando un attacco Denial of Service. Le API del framework ASP.NET Core che utilizzano RegularExpressions passano un timeout.

L'oggetto Regex

Poiché il metodo DumpHRefs può essere chiamato più volte dal codice utente, viene usato il metodo static (Shared in Visual Basic) Regex.Match(String, String, RegexOptions). In questo modo il motore delle espressioni regolari memorizza nella cache l'espressione regolare ed evita il sovraccarico di un'istanza di un nuovo oggetto Regex ogni volta che viene chiamato il metodo. Viene quindi usato un oggetto Match per eseguire un'iterazione in tutte le corrispondenze nella stringa.

private static void DumpHRefs(string inputString)
{
    string hrefPattern = @"href\s*=\s*(?:[""'](?<1>[^""']*)[""']|(?<1>[^>\s]+))";

    try
    {
        Match regexMatch = Regex.Match(inputString, hrefPattern,
                                       RegexOptions.IgnoreCase | RegexOptions.Compiled,
                                       TimeSpan.FromSeconds(1));
        while (regexMatch.Success)
        {
            Console.WriteLine($"Found href {regexMatch.Groups[1]} at {regexMatch.Groups[1].Index}");
            regexMatch = regexMatch.NextMatch();
        }
    }
    catch (RegexMatchTimeoutException)
    {
        Console.WriteLine("The matching operation timed out.");
    }
}
Private Sub DumpHRefs(inputString As String)
    Dim hrefPattern As String = "href\s*=\s*(?:[""'](?<1>[^""']*)[""']|(?<1>[^>\s]+))"

    Try
        Dim regexMatch = Regex.Match(inputString, hrefPattern,
                                     RegexOptions.IgnoreCase Or RegexOptions.Compiled,
                                     TimeSpan.FromSeconds(1))
        Do While regexMatch.Success
            Console.WriteLine($"Found href {regexMatch.Groups(1)} at {regexMatch.Groups(1).Index}.")
            regexMatch = regexMatch.NextMatch()
        Loop
    Catch e As RegexMatchTimeoutException
        Console.WriteLine("The matching operation timed out.")
    End Try
End Sub

Nell'esempio seguente viene illustrata una chiamata al metodo DumpHRefs.

public static void Main()
{
    string inputString = "My favorite web sites include:</P>" +
                         "<A HREF=\"https://learn.microsoft.com/en-us/dotnet/\">" +
                         ".NET Documentation</A></P>" +
                         "<A HREF=\"http://www.microsoft.com\">" +
                         "Microsoft Corporation Home Page</A></P>" +
                         "<A HREF=\"https://devblogs.microsoft.com/dotnet/\">" +
                         ".NET Blog</A></P>";
    DumpHRefs(inputString);
}
// The example displays the following output:
//       Found href https://learn.microsoft.com/dotnet/ at 43
//       Found href http://www.microsoft.com at 114
//       Found href https://devblogs.microsoft.com/dotnet/ at 188
Public Sub Main()
    Dim inputString As String = "My favorite web sites include:</P>" &
                                "<A HREF=""https://learn.microsoft.com/en-us/dotnet/"">" &
                                ".NET Documentation</A></P>" &
                                "<A HREF=""http://www.microsoft.com"">" &
                                "Microsoft Corporation Home Page</A></P>" &
                                "<A HREF=""https://devblogs.microsoft.com/dotnet/"">" &
                                ".NET Blog</A></P>"
    DumpHRefs(inputString)
End Sub
' The example displays the following output:
'       Found href https://learn.microsoft.com/dotnet/ at 43
'       Found href http://www.microsoft.com at 114
'       Found href https://devblogs.microsoft.com/dotnet/ at 188

Il criterio di espressione regolare href\s*=\s*(?:["'](?<1>[^"']*)["']|(?<1>[^>\s]+)) è interpretato nel modo illustrato nella tabella seguente.

Modello Descrizione
href Corrisponde alla stringa letterale "href". La corrispondenza non fa distinzione tra maiuscole e minuscole.
\s* Trovare la corrispondenza di zero o più spazi vuoti.
= Corrisponde al segno di uguale.
\s* Trovare la corrispondenza di zero o più spazi vuoti.
(?: Avviare un gruppo non di acquisizione.
["'](?<1>[^"']*)["'] Trova corrispondenze con una virgoletta o un apostrofo, seguita da un gruppo di acquisizione che corrisponda a qualsiasi carattere diverso da una virgoletta o un apostrofo, seguito da una virgoletta o un apostrofo. Il gruppo denominato 1 è incluso in questo modello.
| OR booleano che corrisponde all'espressione precedente o all'espressione successiva.
(?<1>[^>\s]+) Un gruppo di acquisizione che usa un set negato per trovare corrispondenze con qualsiasi carattere diverso da un segno maggiore o da uno spazio vuoto. Il gruppo denominato 1 è incluso in questo modello.
) Terminare il gruppo non di acquisizione.

Classe di risultati di corrispondenza

I risultati della ricerca vengono archiviati nella classe Match, che offre l'accesso a tutte le sottostringhe estratte dalla ricerca. Tale classe memorizza anche la stringa cercata e l'espressione regolare usata, pertanto è possibile chiamare il metodo Match.NextMatch per eseguire un'altra ricerca a partire dal punto in cui è terminata quella più recente.

Acquisizioni con nome esplicito

Nelle espressioni regolari tradizionali, le parentesi di cattura vengono automaticamente numerate in sequenza. Ciò comporta due problemi. In primo luogo, se un'espressione regolare viene modificata dall'inserimento o rimozione di un set di parentesi, tutto il codice che fa riferimento alle catture numerate deve essere riscritto per riflettere la nuova numerazione. In secondo luogo, poiché diversi set di parentesi spesso vengono usati per specificare due espressioni alternative per una corrispondenza accettabile, potrebbe essere difficile determinare quale delle due espressioni ha effettivamente restituito un risultato.

Per risolvere questi problemi, la classe Regex supporta la sintassi (?<name>…) per l'acquisizione di una corrispondenza in uno slot specificato (che è possibile denominare tramite una stringa o un numero intero, che può essere chiamato più rapidamente). Le corrispondenze alternative per la stessa stringa possono perciò essere tutte indirizzate verso la stessa posizione. In caso di conflitto, l'ultima corrispondenza rilasciata in uno slot è quella corretta. (È tuttavia disponibile un elenco completo di più corrispondenze per un unico slot. Vedere la raccolta Group.Captures per i dettagli.

Vedi anche