Пример регулярного выражения: сканирование для HREFs
В следующем примере показаны поиск и вывод всех значений href="...", а также их позиций в строке.
Предупреждение
При использовании System.Text.RegularExpressions для обработки ненадежных входных данных передайте время ожидания. Злоумышленник может предоставить входные данные RegularExpressions
, вызывая атаку типа "отказ в обслуживании". API платформы ASP.NET Core, использующие RegularExpressions
, передают время ожидания.
Объект Regex
Поскольку метод DumpHRefs
может быть вызван из пользовательского кода несколько раз, он использует метод static
(Shared
в Visual Basic) Regex.Match(String, String, RegexOptions). Это позволяет обработчику регулярных выражений кэшировать регулярное выражение и избежать дополнительной нагрузки, связанной с созданием объекта Regex при каждом вызове метода. Затем объект Match выполняет итерацию по всем совпадениям в строке.
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
В следующем примере показан вызов метода 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
Возможные интерпретации шаблона регулярного выражения href\s*=\s*(?:["'](?<1>[^"']*)["']|(?<1>[^>\s]+))
показаны в следующей таблице.
Расписание | Description |
---|---|
href |
Совпадение с литеральной строкой "href". Сопоставление не учитывает регистр. |
\s* |
Соответствует нулю или нескольким символам пробела. |
= |
Соответствует знаку равенства. |
\s* |
Соответствует нулю или нескольким символам пробела. |
(?: |
Запустите группу без записи. |
["'](?<1>[^"']*)["'] |
Сопоставляйте кавычки или апостроф, за которым следует группа захвата, которая соответствует любому символу, отличному от кавычки или апострофа, за которым следует кавычка или апостроф. В этот шаблон включена группа с именем 1 . |
| | Логический или соответствующий предыдущему выражению или следующему выражению. |
(?<1>[^>\s]+) |
Записывая группа, использующая негритированный набор для сопоставления любого символа, отличного от знака больше или символа пробела. В этот шаблон включена группа с именем 1 . |
) |
Завершите группу без записи. |
Класс результатов сопоставления
Результаты поиска сохраняются в классе Match, который предоставляет доступ ко всем подстрокам, извлеченным в ходе поиска. Также он запоминает искомую строку и использованное регулярное выражение, что позволяет вызвать метод Match.NextMatch для продолжения поиска с того места, где закончился предыдущий.
Явно именованные записи
В обычных регулярных выражениях круглые скобки, обозначающие отдельные шаблоны, автоматически последовательно нумеруются. В связи с этим возникают две проблемы. Во-первых, если регулярное выражение изменяется из-за вставки или удаления пары круглых скобок, все части кода, которые ссылаются на нумерованные шаблоны, необходимо переписать, чтобы отразить новую нумерацию. Во-вторых, вследствие того, что различные пары круглых скобок часто используются для определения двух альтернативных выражений для поиска, трудно определить, какое из двух выражений в действительности вернуло результат.
Для решения этих проблем класс Regex поддерживает синтаксис (?<name>…)
, с помощью которого найденное совпадение можно сохранить в указанной ячейке (которой можно присвоить строковое имя или целочисленное обозначение; числа при этом работают быстрее). Таким образом, если совпадение будет найдено повторно, оно попадет в ту же ячейку. В случае конфликта успешным является то совпадение, которое было помещено в ячейку последним. (Однако доступен полный список нескольких совпадений для одного слота. Дополнительные сведения см. в Group.Captures коллекции.)