Przykład wyrażenia regularnego: wyszukiwanie atrybutów HREF

Poniższy przykład wyszukuje w ciągu wejściowym i wyświetla wszystkie wartości href="…" oraz ich położenia w ciągu.

Warning

Nieograniczone użycie elementu System.Text.RegularExpressions z niezaufanymi danymi wejściowymi może podlegać aplikacjom atakom typu "odmowa usługi". Zapoznaj się z najlepszymi rozwiązaniami dotyczącymi wyrażeń regularnych w .NET, aby uzyskać wskazówki dotyczące bezpiecznego używania .NET wyrażeń regularnych z niezaufanymi danymi wejściowymi.

Obiekt Regex

Ponieważ metoda DumpHRefs może być wywoływana wielokrotnie z kodu użytkownika, używa metody static (Shared w języku Visual Basic) Regex.Match(String, String, RegexOptions). Umożliwia to mechanizmowi wyrażeń regularnych przechowywanie wyrażenia regularnego w pamięci podręcznej oraz pozwala uniknąć narzutu związanego z tworzeniem za każdym razem nowego obiektu Regex, gdy metoda jest wywoływana. Następnie obiekt Match służy do iterowania po wszystkich dopasowaniach w łańcuchu.

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

Poniższy przykład ilustruje wywołanie DumpHRefs metody .

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

Wzorzec href\s*=\s*(?:["'](?<1>[^"']*)["']|(?<1>[^>\s]+)) wyrażenia regularnego jest interpretowany, jak pokazano w poniższej tabeli.

Wzór Description
href Dopasuj literał tekstowy „href”. Dopasowanie jest niewrażliwe na wielkość liter.
\s* Dopasować zero lub więcej znaków odstępu.
= Dopasuj znak równości.
\s* Dopasować zero lub więcej znaków odstępu.
(?: Rozpocznij grupę nieprzechwytującą.
["'](?<1>[^"']*)["'] Dopasuj cudzysłów lub apostrof, a następnie grupę przechwytującą, która dopasowuje dowolny znak inny niż cudzysłów lub apostrof, po czym dopasuj cudzysłów lub apostrof. Grupa o nazwie 1 jest uwzględniona w tym wzorcu.
| Operator logiczny OR, który pasuje do poprzedniego wyrażenia lub następnego wyrażenia.
(?<1>[^>\s]+) Grupa przechwytywania, która używa negowanego zestawu, aby dopasować dowolny znak inny niż znak większy niż znak lub znak odstępu. Grupa o nazwie 1 jest uwzględniona w tym wzorcu.
) Zakończ grupę nieprzechwytującą.

Dopasuj klasę wyników

Wyniki wyszukiwania są przechowywane w Match klasie, która zapewnia dostęp do wszystkich podciągów wyodrębnionych przez wyszukiwanie. Zapamiętuje również wyszukiwany ciąg i używane wyrażenie regularne, dzięki czemu może wywołać Match.NextMatch metodę w celu wykonania innego wyszukiwania, zaczynając od ostatniego zakończonego.

Jawnie nazwane przechwycenia

W tradycyjnych wyrażeniach regularnych przechwytywanie nawiasów jest automatycznie numerowane sekwencyjnie. Prowadzi to do dwóch problemów. Po pierwsze, jeśli wyrażenie regularne zostanie zmodyfikowane przez dodanie lub usunięcie pary nawiasów, cały kod odwołujący się do ponumerowanych grup przechwytywania musi zostać przepisany tak, aby odzwierciedlał nową numerację. Po drugie, ponieważ różne zestawy nawiasów często są używane do zapewnienia dwóch alternatywnych wyrażeń dla akceptowalnego dopasowania, może być trudno określić, które z dwóch wyrażeń rzeczywiście zwróciły wynik.

Aby rozwiązać te problemy, klasa Regex obsługuje składnię (?<name>…), służącą do przechwytywania dopasowania w określonym slocie (slot może być nazwany za pomocą ciągu znaków lub liczby całkowitej; do liczb całkowitych można odwoływać się szybciej). Dzięki temu alternatywne dopasowania dla tego samego ciągu mogą być kierowane w to samo miejsce. W przypadku konfliktu ostatni mecz porzucony w miejscu jest pomyślnym dopasowaniem. (Jednak dostępna jest pełna lista wielu dopasowań dla pojedynczego slotu. Szczegółowe informacje można znaleźć w kolekcji Group.Captures.)

Zobacz także