Udostępnij za pośrednictwem


Wyrażenia regularne platformy .NET

Wyrażenia regularne zapewniają zaawansowaną, elastyczną i wydajną metodę przetwarzania tekstu. Obszerna notacja dopasowywania wzorców w wyrażeniach regularnych umożliwia szybkie analizowanie dużych ilości tekstu na:

  • Znajdź określone wzorce znaków.
  • Zweryfikuj tekst, aby upewnić się, że jest zgodny ze wstępnie zdefiniowanym wzorcem (na przykład adresem e-mail).
  • Wyodrębnianie, edytowanie, zastępowanie lub usuwanie podciągów tekstu.
  • Dodaj wyodrębnione ciągi do kolekcji, aby wygenerować raport.

W przypadku wielu aplikacji, które zajmują się ciągami lub analizowania dużych bloków tekstu, wyrażenia regularne są niezbędnym narzędziem.

Jak działają wyrażenia regularne

Centralnym elementem przetwarzania tekstu z wyrażeniami regularnymi jest aparat wyrażeń regularnych, który jest reprezentowany przez obiekt System.Text.RegularExpressions.Regex na platformie .NET. Przetwarzanie tekstu przy użyciu wyrażeń regularnych wymaga przynajmniej tyle, żeby aparat wyrażeń regularnych był zaopatrzony w następujące dwa elementy informacji:

  • Wzorzec wyrażenia regularnego do zidentyfikowania w tekście.

    Na platformie .NET wzorce wyrażeń regularnych są definiowane przez specjalną składnię lub język, który jest zgodny z wyrażeniami regularnymi Perl 5 i dodaje inne funkcje, takie jak dopasowywanie od prawej do lewej. Aby uzyskać więcej informacji, zobacz Regular Expression Language — Quick Reference.

  • Tekst do przeanalizowania przy użyciu wzorca wyrażenia regularnego.

Metody klasy Regex umożliwiają wykonywanie następujących operacji:

Aby zapoznać się z omówieniem modelu obiektów wyrażeń regularnych, zobacz Model obiektów wyrażeń regularnych.

Aby uzyskać więcej informacji na temat języka wyrażeń regularnych, zobacz Język wyrażeń regularnych — szybki przewodnik lub pobierz i wydrukuj jedną z następujących broszur:

Przykłady wyrażeń regularnych

Klasa String zawiera metody wyszukiwania i zastępowania ciągów znaków, których można użyć, gdy chcesz zlokalizować dosłowne ciągi znaków w większym ciągu znaków. Wyrażenia regularne są najbardziej użyteczne, gdy chcesz zlokalizować jeden z kilku fragmentów w większym ciągu lub gdy chcesz zidentyfikować wzorce w ciągu, co ilustrują poniższe przykłady.

Ostrzeżenie

Podczas używania System.Text.RegularExpressions do przetwarzania niezaufanych danych wejściowych należy przekazać limit czasu. Złośliwy użytkownik może podać dane wejściowe RegularExpressions, powodując atak typu "odmowa usługi" . ASP.NET Core interfejsy API platformy, które używają RegularExpressions przekazują limit czasu.

Wskazówka

System.Web.RegularExpressions Przestrzeń nazw zawiera wiele obiektów wyrażeń regularnych, które implementują wstępnie zdefiniowane wzorce wyrażeń regularnych na potrzeby analizowania ciągów z dokumentów HTML, XML i ASP.NET. Na przykład klasa TagRegex identyfikuje tagi początkowe w ciągu, a klasa CommentRegex identyfikuje komentarze ASP.NET w ciągu.

Przykład 1: Zastępowanie podciągów

Załóżmy, że lista wysyłkowa zawiera nazwy, które czasami zawierają tytuł (Pani, Pani lub Pani) wraz z imieniem i nazwiskiem. Załóżmy, że nie chcesz dołączać tytułów podczas generowania etykiet kopert z listy. W takim przypadku możesz użyć wyrażenia regularnego, aby usunąć tytuły, jak pokazano w poniższym przykładzie:

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

Wzorzec wyrażenia regularnego (Mr\.? |Mrs\.? |Miss |Ms\.? ) pasuje do dowolnego wystąpienia "Pan", "Pan", "Pani", "Pani", "Miss", "Pani", "Pani" lub "Pani". Wywołanie metody Regex.Replace zastępuje dopasowany ciąg String.Empty; innymi słowy, usuwa go z oryginalnego ciągu.

Przykład 2. Identyfikowanie zduplikowanych wyrazów

Przypadkowe duplikowanie wyrazów jest typowym błędem, który tworzą autorzy. Użyj wyrażenia regularnego, aby zidentyfikować zduplikowane wyrazy, jak pokazano w poniższym przykładzie:

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($"{match.Value} (duplicates '{match.Groups[1].Value}') at position {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

Wzorzec wyrażenia regularnego \b(\w+?)\s\1\b można interpretować w następujący sposób:

Wzorzec Interpretacja
\b Rozpocznij od granicy słowa.
(\w+?) Dopasuj co najmniej jeden znak słowa, ale jak najmniejszą liczbę znaków. Razem tworzą grupę, która może być nazywana \1.
\s Dopasuj znak odstępu.
\1 Dopasuj podciąg, który jest równy grupie o nazwie \1.
\b Dopasuj granicę wyrazu.

Metoda Regex.Matches jest wywoływana z opcjami wyrażeń regularnych ustawionymi na RegexOptions.IgnoreCase. W związku z tym operacja dopasowania jest niewrażliwa na wielkość liter, a przykład identyfikuje podciąg "This this" jako duplikację.

Ciąg wejściowy zawiera podciąg „this?” To". Jednak ze względu na interweniujący znak interpunkcyjny nie jest identyfikowany jako duplikacja.

Przykład 3. Dynamiczne tworzenie wyrażenia regularnego wrażliwego na kulturę

Poniższy przykład ilustruje moc wyrażeń regularnych w połączeniu z elastycznością oferowaną przez funkcje globalizacji technologii .NET. Używa obiektu NumberFormatInfo do określenia formatu wartości walutowych w bieżącej kulturze systemu. Następnie używa tych informacji do dynamicznego konstruowania wyrażenia regularnego, które wyodrębnia wartości waluty z tekstu. Dla każdego dopasowania wyodrębnia podgrupę zawierającą tylko ciąg liczbowy, konwertuje ją na wartość Decimal i oblicza sumę bieżącą.

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.

Na komputerze, na którym bieżące ustawienia regionalne to angielski, Stany Zjednoczone (en-US), przykład dynamicznie tworzy wyrażenie regularne \$\s*[-+]?([0-9]{0,3}(,[0-9]{3})*(\.[0-9]+)?). Ten wzorzec wyrażenia regularnego można interpretować w następujący sposób:

Wzorzec Interpretacja
\$ Wyszukaj pojedyncze wystąpienie symbolu dolara ($) w ciągu wejściowym. Ciąg wzorca wyrażenia regularnego zawiera znak backslash, który wskazuje, że symbol dolara powinien być interpretowany literalnie, a nie jako kotwica wyrażenia regularnego. Sam symbol $ wskazuje, że silnik wyrażeń regularnych powinien spróbować rozpocząć dopasowanie na końcu łańcucha znaków. Aby upewnić się, że symbol waluty bieżącej kultury nie jest błędnie interpretowany jako symbol wyrażenia regularnego, przykład wywołuje metodę Regex.Escape, aby znak był pomijany.
\s* Wyszukaj zero lub więcej wystąpień znaku odstępu.
[-+]? Wyszukaj zero lub jedno wystąpienie znaku pozytywnego lub negatywnego.
([0-9]{0,3}(,[0-9]{3})*(\.[0-9]+)?) Nawiasy zewnętrzne definiują to wyrażenie jako grupę przechwytywania lub podwyrażenie. Jeśli zostanie znalezione dopasowanie, informacje o tej części pasującego ciągu można pobrać z drugiego obiektu Group w obiekcie GroupCollection zwróconym przez właściwość Match.Groups. Pierwszy element w kolekcji odpowiada za całe dopasowanie.
[0-9]{0,3} Wyszukaj zero do trzech wystąpień cyfr dziesiętnych od 0 do 9.
(,[0-9]{3})* Wyszukaj zero lub więcej wystąpień separatora grupy, po którym następuje trzy cyfry dziesiętne.
\. Poszukaj pojedynczego wystąpienia separatora dziesiętnego.
[0-9]+ Wyszukaj co najmniej jedną cyfrę dziesiętną.
(\.[0-9]+)? Wyszukaj zero lub jedno wystąpienie separatora dziesiętnego, po którym następuje co najmniej jedna cyfra dziesiętna.

Jeśli każdy podwzorca zostanie znaleziony w ciągu wejściowym, dopasowanie powiedzie się, a obiekt Match zawierający informacje o dopasowaniu zostanie dodany do obiektu MatchCollection.

Nazwa Opis
Język wyrażeń regularnych — podręczny wykaz Zawiera informacje na temat zestawu znaków, operatorów i konstrukcji, których można użyć do definiowania wyrażeń regularnych.
Obiektowy model wyrażeń regularnych Zawiera informacje i przykłady kodu ilustrujące sposób używania klas wyrażeń regularnych.
Szczegóły zachowania wyrażenia regularnego Zawiera informacje o możliwościach i zachowaniu wyrażeń regularnych platformy .NET.
Używanie wyrażeń regularnych w programie Visual Studio

Źródło