Поделиться через


Регулярные выражения .NET

Регулярные выражения предоставляют мощный, гибкий и эффективный метод обработки текста. Обширная нотация регулярных выражений с сопоставлением шаблонов позволяет быстро анализировать большие объемы текста следующими способами:

  • Находить сочетания символов, соответствующие определенным шаблонам.
  • Проверять текст на соответствие заданному шаблону (например, адресу электронной почты).
  • Извлекать, изменять, заменять и удалять подстроки текста.
  • Добавьте извлеченные строки в коллекцию для создания отчета.

Для многих приложений, которые имеют дело с строками или которые анализируют большие блоки текста, регулярные выражения являются незаменимым инструментом.

Как работают регулярные выражения

Центральным элементом обработки текста с регулярными выражениями является обработчик регулярных выражений, который представлен объектом System.Text.RegularExpressions.Regex в .NET. Как минимум, обработка текста с помощью регулярных выражений требует, чтобы обработчик регулярных выражений предоставлялся следующими двумя элементами информации:

  • Шаблон регулярного выражения для идентификации в тексте.

    В .NET шаблоны регулярных выражений определяются специальным синтаксисом или языком, который совместим с регулярными выражениями Perl 5 и добавляет некоторые дополнительные функции, такие как сопоставление справа налево. Дополнительные сведения см. в "Язык регулярных выражений — краткий справочник".

  • Текст для анализа шаблона регулярного выражения.

Методы класса Regex позволяют выполнять следующие операции:

Обзор объектной модели регулярных выражений см. в The Regular Expression Object Model.

Дополнительные сведения о языке регулярных выражений см. в разделе язык регулярных выражений. Краткий справочник или скачивание и печать одного из следующих брошюр:

Примеры регулярных выражений

Класс String включает методы поиска строк и замены, которые можно использовать, если вы хотите найти литеральные строки в большей строке. Регулярные выражения наиболее полезны либо при поиске одной из нескольких подстроок в большей строке, либо при определении шаблонов в строке, как показано в следующих примерах.

Предупреждение

При использовании System.Text.RegularExpressions для обработки ненадежных входных данных передайте время ожидания. Злоумышленник может предоставить входные данные RegularExpressions, что приводит к атаке типа "отказ в обслуживании". API платформы ASP.NET Core, использующие RegularExpressions, передают время ожидания.

Подсказка

Пространство имен System.Web.RegularExpressions содержит ряд объектов регулярного выражения, реализующих предопределенные шаблоны регулярных выражений для синтаксического анализа строк из HTML, XML и ASP.NET документов. Например, класс TagRegex определяет теги запуска в строке, а класс CommentRegex определяет ASP.NET примечания в строке.

Пример 1: Замена подстрок

Предположим, что список рассылки содержит имена, которые иногда включают название (г-н, миссис, мисс или г-жа.) вместе с именем и фамилией. Предположим, вы не хотите включать названия при создании меток конверта из списка. В этом случае можно использовать регулярное выражение для удаления заголовков, как показано в следующем примере:

using System;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      string pattern = "(Mr\\.? |Mrs\\.? |Miss |Ms\\.? )";
      string[] names = { "Mr. Henry Hunt", "Ms. Sara Samuels",
                         "Abraham Adams", "Ms. Nicole Norris" };
      foreach (string name in names)
         Console.WriteLine(Regex.Replace(name, pattern, String.Empty));
   }
}
// The example displays the following output:
//    Henry Hunt
//    Sara Samuels
//    Abraham Adams
//    Nicole Norris
Imports System.Text.RegularExpressions

Module Example
    Public Sub Main()
        Dim pattern As String = "(Mr\.? |Mrs\.? |Miss |Ms\.? )"
        Dim names() As String = {"Mr. Henry Hunt", "Ms. Sara Samuels", _
                                  "Abraham Adams", "Ms. Nicole Norris"}
        For Each name As String In names
            Console.WriteLine(Regex.Replace(name, pattern, String.Empty))
        Next
    End Sub
End Module
' The example displays the following output:
'    Henry Hunt
'    Sara Samuels
'    Abraham Adams
'    Nicole Norris

Шаблон регулярного выражения (Mr\.? |Mrs\.? |Miss |Ms\.? ) соответствует любому вхождениям "г-н", "г-жа", "Миссис", "Мисс", "Г-жа", или "г-жа". Вызов метода Regex.Replace заменяет соответствующую строку String.Empty; другими словами, он удаляет его из исходной строки.

Пример 2. Определение повторяющихся слов

Случайное дублирование слов — это распространенная ошибка, которую делают авторы. Используйте регулярное выражение для идентификации повторяющихся слов, как показано в следующем примере:

using System;
using System.Text.RegularExpressions;

public class Class1
{
   public static void Main()
   {
      string pattern = @"\b(\w+?)\s\1\b";
      string input = "This this is a nice day. What about this? This tastes good. I saw a a dog.";
      foreach (Match match in Regex.Matches(input, pattern, RegexOptions.IgnoreCase))
         Console.WriteLine("{0} (duplicates '{1}') at position {2}",
                           match.Value, match.Groups[1].Value, match.Index);
   }
}
// The example displays the following output:
//       This this (duplicates 'This') at position 0
//       a a (duplicates 'a') at position 66
Imports System.Text.RegularExpressions

Module modMain
    Public Sub Main()
        Dim pattern As String = "\b(\w+?)\s\1\b"
        Dim input As String = "This this is a nice day. What about this? This tastes good. I saw a a dog."
        For Each match As Match In Regex.Matches(input, pattern, RegexOptions.IgnoreCase)
            Console.WriteLine("{0} (duplicates '{1}') at position {2}", _
                              match.Value, match.Groups(1).Value, match.Index)
        Next
    End Sub
End Module
' The example displays the following output:
'       This this (duplicates 'This') at position 0
'       a a (duplicates 'a') at position 66

Шаблон регулярного выражения \b(\w+?)\s\1\b можно интерпретировать следующим образом:

Рисунок Интерпретация
\b Начните с границы слова.
(\w+?) Найти одно или несколько буквенных символов, но минимальное количество. Вместе они образуют группу, которую можно называть \1.
\s Соответствует символу пробела.
\1 Соответствует подстроке, идентичной группе с именем \1.
\b Найти границу слова.

Метод Regex.Matches вызывается с параметрами регулярного выражения, установленными для RegexOptions.IgnoreCase. Поэтому операция сопоставления не учитывает регистр, а пример определяет подстроку "Это это" как дублирование.

Входная строка включает подстроку "это? Это". Тем не менее, из-за пересекающегося знака препинания он не определяется как дублирование.

Пример 3. Динамическое создание регулярного выражения с учетом языка и региональных параметров

В следующем примере демонстрируются возможности регулярных выражений в сочетании с гибкостью, которую предоставляют функции глобализации .NET. Он использует объект NumberFormatInfo для определения формата значений валют в текущей культуре системы. Затем эта информация используется для динамического создания регулярного выражения, извлекающего значения валют из текста. Для каждого совпадения он извлекает подгруппу, содержащую только числовую строку, преобразует ее в значение Decimal и вычисляет нарастающий итог.

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      // Define text to be parsed.
      string input = "Office expenses on 2/13/2008:\n" +
                     "Paper (500 sheets)                      $3.95\n" +
                     "Pencils (box of 10)                     $1.00\n" +
                     "Pens (box of 10)                        $4.49\n" +
                     "Erasers                                 $2.19\n" +
                     "Ink jet printer                        $69.95\n\n" +
                     "Total Expenses                        $ 81.58\n";

      // Get current culture's NumberFormatInfo object.
      NumberFormatInfo nfi = CultureInfo.CurrentCulture.NumberFormat;
      // Assign needed property values to variables.
      string currencySymbol = nfi.CurrencySymbol;
      bool symbolPrecedesIfPositive = nfi.CurrencyPositivePattern % 2 == 0;
      string groupSeparator = nfi.CurrencyGroupSeparator;
      string decimalSeparator = nfi.CurrencyDecimalSeparator;

      // Form regular expression pattern.
      string pattern = Regex.Escape( symbolPrecedesIfPositive ? currencySymbol : "") +
                       @"\s*[-+]?" + "([0-9]{0,3}(" + groupSeparator + "[0-9]{3})*(" +
                       Regex.Escape(decimalSeparator) + "[0-9]+)?)" +
                       (! symbolPrecedesIfPositive ? currencySymbol : "");
      Console.WriteLine( "The regular expression pattern is:");
      Console.WriteLine("   " + pattern);

      // Get text that matches regular expression pattern.
      MatchCollection matches = Regex.Matches(input, pattern,
                                              RegexOptions.IgnorePatternWhitespace);
      Console.WriteLine($"Found {matches.Count} matches.");

      // Get numeric string, convert it to a value, and add it to List object.
      List<decimal> expenses = new List<Decimal>();

      foreach (Match match in matches)
         expenses.Add(Decimal.Parse(match.Groups[1].Value));

      // Determine whether total is present and if present, whether it is correct.
      decimal total = 0;
      foreach (decimal value in expenses)
         total += value;

      if (total / 2 == expenses[expenses.Count - 1])
         Console.WriteLine($"The expenses total {expenses[expenses.Count - 1]:C2}.");
      else
         Console.WriteLine($"The expenses total {total:C2}.");
   }
}
// The example displays the following output:
//       The regular expression pattern is:
//          \$\s*[-+]?([0-9]{0,3}(,[0-9]{3})*(\.[0-9]+)?)
//       Found 6 matches.
//       The expenses total $81.58.
Imports System.Collections.Generic
Imports System.Globalization
Imports System.Text.RegularExpressions

Public Module Example
    Public Sub Main()
        ' Define text to be parsed.
        Dim input As String = "Office expenses on 2/13/2008:" + vbCrLf + _
                              "Paper (500 sheets)                      $3.95" + vbCrLf + _
                              "Pencils (box of 10)                     $1.00" + vbCrLf + _
                              "Pens (box of 10)                        $4.49" + vbCrLf + _
                              "Erasers                                 $2.19" + vbCrLf + _
                              "Ink jet printer                        $69.95" + vbCrLf + vbCrLf + _
                              "Total Expenses                        $ 81.58" + vbCrLf
        ' Get current culture's NumberFormatInfo object.
        Dim nfi As NumberFormatInfo = CultureInfo.CurrentCulture.NumberFormat
        ' Assign needed property values to variables.
        Dim currencySymbol As String = nfi.CurrencySymbol
        Dim symbolPrecedesIfPositive As Boolean = CBool(nfi.CurrencyPositivePattern Mod 2 = 0)
        Dim groupSeparator As String = nfi.CurrencyGroupSeparator
        Dim decimalSeparator As String = nfi.CurrencyDecimalSeparator

        ' Form regular expression pattern.
        Dim pattern As String = Regex.Escape(CStr(IIf(symbolPrecedesIfPositive, currencySymbol, ""))) + _
                                "\s*[-+]?" + "([0-9]{0,3}(" + groupSeparator + "[0-9]{3})*(" + _
                                Regex.Escape(decimalSeparator) + "[0-9]+)?)" + _
                                CStr(IIf(Not symbolPrecedesIfPositive, currencySymbol, ""))
        Console.WriteLine("The regular expression pattern is: ")
        Console.WriteLine("   " + pattern)

        ' Get text that matches regular expression pattern.
        Dim matches As MatchCollection = Regex.Matches(input, pattern, RegexOptions.IgnorePatternWhitespace)
        Console.WriteLine("Found {0} matches. ", matches.Count)

        ' Get numeric string, convert it to a value, and add it to List object.
        Dim expenses As New List(Of Decimal)

        For Each match As Match In matches
            expenses.Add(Decimal.Parse(match.Groups.Item(1).Value))
        Next

        ' Determine whether total is present and if present, whether it is correct.
        Dim total As Decimal
        For Each value As Decimal In expenses
            total += value
        Next

        If total / 2 = expenses(expenses.Count - 1) Then
            Console.WriteLine("The expenses total {0:C2}.", expenses(expenses.Count - 1))
        Else
            Console.WriteLine("The expenses total {0:C2}.", total)
        End If
    End Sub
End Module
' The example displays the following output:
'       The regular expression pattern is:
'          \$\s*[-+]?([0-9]{0,3}(,[0-9]{3})*(\.[0-9]+)?)
'       Found 6 matches.
'       The expenses total $81.58.

На компьютере, на котором текущий язык и региональные параметры — английский (США) (en-US), пример динамически создает регулярное выражение \$\s*[-+]?([0-9]{0,3}(,[0-9]{3})*(\.[0-9]+)?). Этот шаблон регулярного выражения можно интерпретировать следующим образом:

Рисунок Интерпретация
\$ Найдите одно вхождение символа доллара ($) в входной строке. Строка шаблона регулярного выражения содержит обратную косую черту, указывающую, что символ доллара должен быть интерпретирован буквально, а не как привязка регулярного выражения. Символ $ указывает, что механизм регулярных выражений должен попытаться начать совпадение с конца строки. Чтобы убедиться, что символ валюты текущего языка и региональных параметров не интерпретируется как символ регулярного выражения, в примере вызывается метод Regex.Escape для экранирования символа.
\s* Найдите ноль или больше вхождений символа пробела.
[-+]? Найдите ноль или одно вхождение положительного или отрицательного знака.
([0-9]{0,3}(,[0-9]{3})*(\.[0-9]+)?) Внешние скобки определяют это выражение как записывающую группу или подэкспрессию. Если совпадение найдено, сведения об этой части соответствующей строки можно получить из второго объекта Group в объекте GroupCollection, возвращаемом свойством Match.Groups. Первый элемент в коллекции представляет полное совпадение.
[0-9]{0,3} Найдите от нуля до трех появлений цифр от 0 до 9.
(,[0-9]{3})* Ищите ноль или более последовательностей группового разделителя, за которым следуют три цифры.
\. Найдите одно вхождение десятичного разделителя.
[0-9]+ Найдите одну или несколько десятичных цифр.
(\.[0-9]+)? Найдите ноль или одно вхождение десятичного разделителя, за которым следует по крайней мере одна десятичная цифра.

Если каждый подпаттерн находится во входной строке, совпадение завершается успешно, и объект Match, содержащий сведения о совпадении, добавляется в объект MatchCollection.

Заголовок Описание
Элементы языка регулярных выражений — краткий справочник Предоставляет сведения о наборе символов, операторов и конструкций, которые можно использовать для определения регулярных выражений.
Модель объекта регулярного выражения Предоставляет сведения и примеры кода, иллюстрирующие использование классов регулярных выражений.
Подробная информация о поведении регулярных выражений Предоставляет сведения о возможностях и поведении регулярных выражений .NET.
Использование регулярных выражений в Visual Studio

Ссылка