Udostępnij za pośrednictwem


System.Text.RegularExpressions.Regex, klasa

Ten artykuł zawiera dodatkowe uwagi dotyczące dokumentacji referencyjnej dla tego interfejsu API.

Klasa Regex reprezentuje silnik wyrażeń regularnych .NET. Tej klasy można użyć do:

  • Szybkie analizowanie dużych ilości tekstu w celu znalezienia określonych wzorców znaków.
  • Wyodrębnianie, edytowanie, zastępowanie lub usuwanie podciągów tekstowych.
  • Dodaj wyodrębnione ciągi do kolekcji, aby wygenerować raport.

Uwaga

Jeśli chcesz zweryfikować ciąg, określając, czy jest on zgodny z określonym wzorcem wyrażenia regularnego, możesz użyć System.Configuration.RegexStringValidator klasy .

Aby używać wyrażeń regularnych, należy zdefiniować wzorzec, który ma być identyfikowany w strumieniu tekstowym przy użyciu składni opisanej w języku wyrażeń regularnych — krótki przewodnik. Następnie możesz opcjonalnie stworzyć obiekt Regex. Na koniec wywołujesz metodę, która wykonuje jakąś operację, na przykład zamieniając tekst zgodny ze wzorcem wyrażenia regularnego lub identyfikując dopasowanie wzorca.

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

Szybki przewodnik w formacie Word (.docx)Szybki przewodnik w formacie PDF (.pdf)

Regex kontra Metody String

Klasa System.String zawiera kilka metod wyszukiwania i porównywania, których można używać do dopasowywania wzorca z tekstem. Na przykład metody String.Contains, String.EndsWith i String.StartsWith określają, czy wystąpienie ciągu zawiera określony podciąg, a metody String.IndexOf, String.IndexOfAny, String.LastIndexOf i String.LastIndexOfAny zwracają pozycję początkową określonego podciągu w ciągu. Użyj metod System.String klasy podczas wyszukiwania określonego ciągu. Regex Użyj klasy podczas wyszukiwania określonego wzorca w ciągu. Aby uzyskać więcej informacji i przykładów, zobacz Wyrażenia regularne platformy .NET.

Metody statyczne a metody instancji

Po zdefiniowaniu wzorca wyrażenia regularnego można podać go do aparatu wyrażeń regularnych na jeden z dwóch sposobów:

  • Poprzez utworzenie instancji obiektu Regex, który reprezentuje wyrażenie regularne. W tym celu należy przekazać wzorzec wyrażenia regularnego do konstruktora Regex . Obiekt Regex jest niezmienny; kiedy utworzysz wystąpienie obiektu Regex za pomocą wyrażenia regularnego, wyrażenie regularne tego obiektu nie może być zmienione.

  • Podając zarówno wyrażenie regularne, jak i tekst do przeszukania do metody static (Shared w Visual Basic) Regex. Dzięki temu można używać wyrażenia regularnego bez potrzeby jawnego tworzenia obiektu Regex.

Wszystkie Regex metody identyfikacji wzorca obejmują zarówno przeciążenia statyczne, jak i instancji.

Aparat wyrażeń regularnych musi skompilować określony wzorzec, zanim będzie można użyć wzorca. Ponieważ Regex obiekty są niezmienne, jest to jednorazowa procedura wykonywana po Regex wywołaniu konstruktora klasy lub metody statycznej. Aby wyeliminować konieczność wielokrotnego kompilowania pojedynczego wyrażenia regularnego, aparat wyrażeń regularnych buforuje skompilowane wyrażenia regularne używane w wywołaniach metod statycznych. W rezultacie metody dopasowywania wzorców wyrażeń regularnych oferują porównywalną wydajność dla metod statycznych i wystąpień. Jednak buforowanie może niekorzystnie wpłynąć na wydajność w następujących dwóch przypadkach:

  • W przypadku używania wywołań metod statycznych z dużą liczbą wyrażeń regularnych. Domyślnie aparat wyrażeń regularnych buforuje 15 ostatnio używanych statycznych wyrażeń regularnych. Jeśli aplikacja używa więcej niż 15 statycznych wyrażeń regularnych, niektóre wyrażenia regularne muszą być ponownie skompilowane. Aby zapobiec ponownej kompilacji, można zwiększyć Regex.CacheSize właściwość .

  • Podczas inicjalizacji nowych obiektów Regex za pomocą wyrażeń regularnych, które zostały wcześniej skompilowane. Na przykład poniższy kod definiuje wyrażenie regularne w celu zlokalizowania zduplikowanych wyrazów w strumieniu tekstowym. Mimo że w przykładzie użyto pojedynczego wyrażenia regularnego, dla przetworzenia każdej linii tekstu jest tworzone nowe wystąpienie obiektu Regex. Spowoduje to ponowne skompilowanie wyrażenia regularnego z każdą iterację pętli.

    StreamReader sr = new StreamReader(filename);
    string input;
    string pattern = @"\b(\w+)\s\1\b";
    while (sr.Peek() >= 0)
    {
       input = sr.ReadLine();
       Regex rgx = new Regex(pattern, RegexOptions.IgnoreCase);
       MatchCollection matches = rgx.Matches(input);
       if (matches.Count > 0)
       {
          Console.WriteLine($"{input} ({matches.Count} matches):");
          foreach (Match match in matches)
             Console.WriteLine("   " + match.Value);
       }
    }
    sr.Close();
    
    Dim sr As New StreamReader(filename)
    Dim input As String
    Dim pattern As String = "\b(\w+)\s\1\b"
    Do While sr.Peek() >= 0
       input = sr.ReadLine()
       Dim rgx As New Regex(pattern, RegexOptions.IgnoreCase)
       Dim matches As MatchCollection = rgx.Matches(input)
       If matches.Count > 0 Then
          Console.WriteLine("{0} ({1} matches):", input, matches.Count)
          For Each match As Match In matches
             Console.WriteLine("   " + match.Value)
          Next   
       End If
    Loop
    sr.Close()
    

    Aby uniknąć ponownej kompilacji, należy utworzyć wystąpienie pojedynczego obiektu Regex, który jest dostępny dla wszystkich części kodu, które go wymagają, jak pokazano w poniższym przepisanym przykładzie.

    StreamReader sr = new StreamReader(filename);
    string input;
    string pattern = @"\b(\w+)\s\1\b";
    Regex rgx = new Regex(pattern, RegexOptions.IgnoreCase);
    
    while (sr.Peek() >= 0)
    {
       input = sr.ReadLine();
       MatchCollection matches = rgx.Matches(input);
       if (matches.Count > 0)
       {
          Console.WriteLine($"{input} ({matches.Count} matches):");
          foreach (Match match in matches)
             Console.WriteLine("   " + match.Value);
       }
    }
    sr.Close();
    
    Dim sr As New StreamReader(filename)
    Dim input As String
    Dim pattern As String = "\b(\w+)\s\1\b"
    Dim rgx As New Regex(pattern, RegexOptions.IgnoreCase)
    Do While sr.Peek() >= 0
       input = sr.ReadLine()
       Dim matches As MatchCollection = rgx.Matches(input)
       If matches.Count > 0 Then
          Console.WriteLine("{0} ({1} matches):", input, matches.Count)
          For Each match As Match In matches
             Console.WriteLine("   " + match.Value)
          Next   
       End If
    Loop
    sr.Close()
    

Wykonywanie operacji wyrażeń regularnych

Niezależnie od tego, czy zdecydujesz się utworzyć wystąpienie obiektu Regex i wywołać jego metody, czy wywołać metody statyczne, klasa Regex oferuje następujące funkcje dopasowywania wzorców.

  • Walidacja dopasowania. Wywołujesz metodę IsMatch, aby określić, czy istnieje dopasowanie.

  • Wyodrębnienie pojedynczego wyniku. Metoda Match służy do pobierania obiektu Match, który reprezentuje pierwsze dopasowanie w ciągu lub w części ciągu. Kolejne dopasowania można pobrać, wywołując metodę Match.NextMatch .

  • Pobieranie wszystkich dopasowań. Wywołasz metodę MatchesSystem.Text.RegularExpressions.MatchCollection , aby pobrać obiekt reprezentujący wszystkie dopasowania znalezione w ciągu lub w części ciągu.

  • Zamiana dopasowanego tekstu. Wywołujesz metodę Replace w celu zastąpienia dopasowanego tekstu. Tekst zastępczy można również zdefiniować za pomocą wyrażenia regularnego. Ponadto niektóre Replace metody obejmują MatchEvaluator parametr, który umożliwia programowe definiowanie tekstu zastępczego.

  • Tworzenie tablicy ciągów utworzonej na podstawie części ciągu wejściowego. Wywołujesz metodę Split w celu podzielenia ciągu wejściowego w pozycjach zdefiniowanych przez wyrażenie regularne.

Oprócz metod Regex dopasowywania wzorców klasa zawiera kilka metod specjalnego przeznaczenia:

  • Metoda Escape ucieczki od wszystkich znaków, które mogą być interpretowane jako operatory wyrażeń regularnych w wyrażeniu regularnym lub ciągu wejściowym.
  • Metoda Unescape usuwa te znaki ucieczki.
  • Metoda CompileToAssembly tworzy zestaw zawierający wstępnie zdefiniowane wyrażenia regularne. Platforma .NET zawiera przykłady tych zestawów specjalnego przeznaczenia w System.Web.RegularExpressions przestrzeni nazw.

Definiowanie wartości limitu czasu

Platforma .NET obsługuje w pełni funkcjonalny język wyrażeń regularnych, który zapewnia znaczną moc i elastyczność dopasowywania wzorców. Jednak moc i elastyczność są kosztowne: ryzyko niskiej wydajności. Wyrażenia regularne, które działają źle, są zaskakująco łatwe do utworzenia. W niektórych przypadkach operacje wyrażeń regularnych, które opierają się na nadmiernym przetwarzaniu wstecznym, mogą wydawać się przestawać odpowiadać, gdy przetwarzają tekst prawie zgodny ze wzorcem wyrażenia regularnego. Aby uzyskać więcej informacji na temat aparatu wyrażeń regularnych platformy .NET, zobacz Szczegóły zachowania wyrażenia regularnego. Aby uzyskać więcej informacji na temat nadmiernego wycofywania, zobacz Wycofywanie.

Począwszy od programu .NET Framework 4.5, można zdefiniować przedział czasu dla dopasowań wyrażeń regularnych, aby ograniczyć nadmierne wycofywanie. W zależności od wzorca wyrażenia regularnego i tekstu wejściowego czas wykonywania może przekraczać określony interwał limitu czasu, ale nie spędzi więcej czasu na wycofywanie niż określony interwał limitu czasu. Jeśli aparat wyrażeń regularnych przekroczy limit czasu, zgłasza wyjątek RegexMatchTimeoutException. W większości przypadków uniemożliwia to aparatowi wyrażeń regularnych marnowanie mocy obliczeniowej przez próbę dopasowania tekstu niemal do wzorca wyrażenia regularnego. Może to również wskazywać, że interwał limitu czasu został ustawiony zbyt nisko lub że bieżące obciążenie maszyny spowodowało ogólne obniżenie wydajności.

Sposób obsługi wyjątku zależy od przyczyny wyjątku. Jeśli wyjątek występuje, ponieważ okres limitu czasu jest ustawiony zbyt krótko lub z powodu zbytniego obciążenia systemu, możesz zwiększyć okres limitu czasu i ponowić próbę dopasowania. Jeśli wyjątek występuje, ponieważ wyrażenie regularne opiera się na nadmiernym wycofywaniu, można założyć, że dopasowanie nie istnieje, a opcjonalnie można zarejestrować informacje, które pomogą ci zmodyfikować wzorzec wyrażenia regularnego.

Limit czasu można ustawić, wywołując Regex(String, RegexOptions, TimeSpan) konstruktor przy tworzeniu obiektu wyrażenia regularnego. W przypadku metod statycznych można ustawić interwał limitu czasu, wywołując przeciążenie pasującej metody, która ma matchTimeout parametr. Jeśli jawnie nie ustawisz wartości limitu czasu, domyślna wartość limitu czasu zostanie określona w następujący sposób:

  • Używając wartości limitu czasu dla całej aplikacji, jeśli istnieje. pl-PL: Ustaw wartość limitu czasu dla całej aplikacji, wywołując AppDomain.SetData metodę, aby przypisać reprezentację TimeSpan ciągu wartości do REGEX_DEFAULT_MATCH_TIMEOUT właściwości.
  • Używając wartości InfiniteMatchTimeout, jeśli nie ustawiono wartości limitu czasu dla całej aplikacji.

Ważne

Zalecamy ustawienie wartości limitu czasu we wszystkich operacjach dopasowywania wzorców wyrażeń regularnych. Aby uzyskać więcej informacji, zobacz Najlepsze rozwiązania dotyczące wyrażeń regularnych.

Przykłady

W poniższym przykładzie użyto wyrażenia regularnego, aby sprawdzić powtarzające się wystąpienia wyrazów w ciągu. Wyrażenie \b(?<word>\w+)\s+(\k<word>)\b regularne można interpretować, jak pokazano w poniższej tabeli.

Wzorzec opis
\b Rozpocznij dopasowanie na granicy słowa.
(?<word>\w+) Dopasuj co najmniej jeden znak słowa do granicy wyrazu. Nadaj tej przechwyconej grupie wordnazwę .
\s+ Dopasuj co najmniej jeden znak odstępu.
(\k<word>) Dopasuj przechwyconą grupę o nazwie word.
\b Dopasuj granicę wyrazu.
using System;
using System.Text.RegularExpressions;

public class Test
{
    public static void Main ()
    {
        // Define a regular expression for repeated words.
        Regex rx = new Regex(@"\b(?<word>\w+)\s+(\k<word>)\b",
          RegexOptions.Compiled | RegexOptions.IgnoreCase);

        // Define a test string.
        string text = "The the quick brown fox  fox jumps over the lazy dog dog.";

        // Find matches.
        MatchCollection matches = rx.Matches(text);

        // Report the number of matches found.
        Console.WriteLine($"{matches.Count} matches found in:\n   {text}");

        // Report on each match.
        foreach (Match match in matches)
        {
            GroupCollection groups = match.Groups;
            Console.WriteLine($"'{groups["word"].Value}' repeated at positions {groups[0].Index} and {groups[1].Index}");
        }
    }
}

// The example produces the following output to the console:
//       3 matches found in:
//          The the quick brown fox  fox jumps over the lazy dog dog.
//       'The' repeated at positions 0 and 4
//       'fox' repeated at positions 20 and 25
//       'dog' repeated at positions 49 and 53
Imports System.Text.RegularExpressions

Public Module Test

    Public Sub Main()
        ' Define a regular expression for repeated words.
        Dim rx As New Regex("\b(?<word>\w+)\s+(\k<word>)\b", _
               RegexOptions.Compiled Or RegexOptions.IgnoreCase)

        ' Define a test string.        
        Dim text As String = "The the quick brown fox  fox jumps over the lazy dog dog."
        
        ' Find matches.
        Dim matches As MatchCollection = rx.Matches(text)

        ' Report the number of matches found.
        Console.WriteLine("{0} matches found in:", matches.Count)
        Console.WriteLine("   {0}", text)

        ' Report on each match.
        For Each match As Match In matches
            Dim groups As GroupCollection = match.Groups
            Console.WriteLine("'{0}' repeated at positions {1} and {2}", _ 
                              groups.Item("word").Value, _
                              groups.Item(0).Index, _
                              groups.Item(1).Index)
        Next
    End Sub
End Module
' The example produces the following output to the console:
'       3 matches found in:
'          The the quick brown fox  fox jumps over the lazy dog dog.
'       'The' repeated at positions 0 and 4
'       'fox' repeated at positions 20 and 25
'       'dog' repeated at positions 49 and 53

W następnym przykładzie pokazano użycie wyrażenia regularnego w celu sprawdzenia, czy ciąg reprezentuje wartość waluty, czy ma poprawny format reprezentujący wartość waluty. W tym przypadku wyrażenie regularne jest tworzone dynamicznie na podstawie właściwości NumberFormatInfo.CurrencyDecimalSeparator, CurrencyDecimalDigits, NumberFormatInfo.CurrencySymbol, NumberFormatInfo.NegativeSign i NumberFormatInfo.PositiveSign dla kultury języka angielskiego (Stany Zjednoczone). Wynikowe wyrażenie regularne to ^\s*[\+-]?\s?\$?\s?(\d*\.?\d{2}?){1}$. To wyrażenie regularne można interpretować, jak pokazano w poniższej tabeli.

Wzorzec opis
^ Zacznij od początku ciągu.
\s* Dopasować zero lub więcej znaków odstępu.
[\+-]? Dopasuj zero lub jedno wystąpienie znaku dodatniego lub znaku ujemnego.
\s? Dopasowuje zero lub jeden biały znak odstępu.
\$? Dopasuj zero lub jedno wystąpienie znaku dolara.
\s? Dopasowuje zero lub jeden biały znak odstępu.
\d* Dopasuj zero lub więcej cyfr dziesiętnych.
\.? Dopasuj symbol zero lub jeden punkt dziesiętny.
(\d{2})? Przechwytywanie grupy 1: Dopasuj dwie cyfry dziesiętne zero lub jeden raz.
(\d*\.?(\d{2})?){1} Dopasuj wzorzec cyfr całkowitych i ułamkowych rozdzielonych symbolem separatora dziesiętnego dokładnie raz.
$ Dopasuj koniec ciągu znaków.

W tym przypadku wyrażenie regularne zakłada, że prawidłowy ciąg waluty nie zawiera symboli separatora grupy oraz że zawiera albo brak cyfr ułamkowych, albo liczbę cyfr ułamkowych zdefiniowaną przez właściwość określonej kultury CurrencyDecimalDigits.

using System;
using System.Globalization;
using System.Text.RegularExpressions;

public class Example
{
    public static void Main()
    {
        // Get the en-US NumberFormatInfo object to build the regular 
        // expression pattern dynamically.
        NumberFormatInfo nfi = CultureInfo.GetCultureInfo("en-US").NumberFormat;

        // Define the regular expression pattern.
        string pattern;
        pattern = @"^\s*[";
        // Get the positive and negative sign symbols.
        pattern += Regex.Escape(nfi.PositiveSign + nfi.NegativeSign) + @"]?\s?";
        // Get the currency symbol.
        pattern += Regex.Escape(nfi.CurrencySymbol) + @"?\s?";
        // Add integral digits to the pattern.
        pattern += @"(\d*";
        // Add the decimal separator.
        pattern += Regex.Escape(nfi.CurrencyDecimalSeparator) + "?";
        // Add the fractional digits.
        pattern += @"(\d{";
        // Determine the number of fractional digits in currency values.
        pattern += nfi.CurrencyDecimalDigits.ToString() + "})?){1}$";

        Console.WriteLine($"Pattern is {pattern}\n");

        Regex rgx = new Regex(pattern);

        // Define some test strings.
        string[] tests = { "-42", "19.99", "0.001", "100 USD",
                         ".34", "0.34", "1,052.21", "$10.62",
                         "+1.43", "-$0.23" };

        // Check each test string against the regular expression.
        foreach (string test in tests)
        {
            if (rgx.IsMatch(test))
                Console.WriteLine($"{test} is a currency value.");
            else
                Console.WriteLine($"{test} is not a currency value.");
        }
    }
}
// The example displays the following output:
//       Pattern is ^\s*[\+-]?\s?\$?\s?(\d*\.?(\d{2})?){1}$
//
//       -42 is a currency value.
//       19.99 is a currency value.
//       0.001 is not a currency value.
//       100 USD is not a currency value.
//       .34 is a currency value.
//       0.34 is a currency value.
//       1,052.21 is not a currency value.
//       $10.62 is a currency value.
//       +1.43 is a currency value.
//       -$0.23 is a currency value.
Imports System.Globalization
Imports System.Text.RegularExpressions

Public Module Example
   Public Sub Main()
      ' Get the current NumberFormatInfo object to build the regular 
      ' expression pattern dynamically.
      Dim nfi As NumberFormatInfo = CultureInfo.GetCultureInfo("en-US").NumberFormat

      ' Define the regular expression pattern.
      Dim pattern As String 
      pattern = "^\s*["
      ' Get the positive and negative sign symbols.
      pattern += Regex.Escape(nfi.PositiveSign + nfi.NegativeSign) + "]?\s?"
      ' Get the currency symbol.
      pattern += Regex.Escape(nfi.CurrencySymbol) + "?\s?"
      ' Add integral digits to the pattern.
      pattern += "(\d*"
      ' Add the decimal separator.
      pattern += Regex.Escape(nfi.CurrencyDecimalSeparator) + "?"
      ' Add the fractional digits.
      pattern += "(\d{"
      ' Determine the number of fractional digits in currency values.
      pattern += nfi.CurrencyDecimalDigits.ToString() + "})?){1}$"
      
      Console.WriteLine("Pattern is {0}", pattern)
      Console.WriteLine()
      
      Dim rgx As New Regex(pattern)

      ' Define some test strings.
      Dim tests() As String = {"-42", "19.99", "0.001", "100 USD", _
                               ".34", "0.34", "1,052.21", "$10.62", _
                               "+1.43", "-$0.23" }

      ' Check each test string against the regular expression.
      For Each test As String In tests
         If rgx.IsMatch(test) Then
            Console.WriteLine("{0} is a currency value.", test)
         Else
            Console.WriteLine("{0} is not a currency value.", test)
         End If
      Next
   End Sub
End Module
' The example displays the following output:
'       Pattern is ^\s*[\+-]?\s?\$?\s?(\d*\.?(\d{2})?){1}$
'
'       -42 is a currency value.
'       19.99 is a currency value.
'       0.001 is not a currency value.
'       100 USD is not a currency value.
'       .34 is a currency value.
'       0.34 is a currency value.
'       1,052.21 is not a currency value.
'       $10.62 is a currency value.
'       +1.43 is a currency value.
'       -$0.23 is a currency value.

Ponieważ wyrażenie regularne w tym przykładzie jest tworzone dynamicznie, nie wiesz w czasie projektowania, czy symbol waluty, znak dziesiętny lub pozytywne i ujemne oznaki określonej kultury (en-US w tym przykładzie) mogą być błędnie interpretowane przez aparat wyrażeń regularnych jako operatory języka wyrażeń regularnych. Aby zapobiec błędnej interpretacji, przykład przekazuje każdy dynamicznie wygenerowany ciąg do Escape metody .