Dela via


System.Text.RegularExpressions.Regex-klass

Den här artikeln innehåller ytterligare kommentarer till referensdokumentationen för det här API:et.

Klassen Regex representerar . NET:s motor för reguljära uttryck. Du kan använda den här klassen för att:

  • Parsa snabbt stora mängder text för att hitta specifika teckenmönster.
  • Extrahera, redigera, ersätta eller ta bort textundersträngar.
  • Lägg till de extraherade strängarna i en samling för att generera en rapport.

Kommentar

Om du vill verifiera en sträng genom att avgöra om den överensstämmer med ett visst mönster för reguljära uttryck kan du använda System.Configuration.RegexStringValidator klassen.

Om du vill använda reguljära uttryck definierar du det mönster som du vill identifiera i en textström med hjälp av syntaxen som dokumenteras i reguljärt uttrycksspråk – snabbreferens. Sedan kan du välja att instansiera ett Regex objekt. Slutligen anropar du en metod som utför en viss åtgärd, till exempel att ersätta text som matchar mönster för reguljära uttryck eller identifiera en mönstermatchning.

Mer information om språket för reguljära uttryck finns i Språk för reguljära uttryck – snabbreferens eller ladda ned och skriva ut en av dessa broschyrer:

Snabbreferens i Word-format(.docx) i PDF-format (.pdf)

Regex jämfört med strängmetoder

Klassen System.String innehåller flera sök- och jämförelsemetoder som du kan använda för att utföra mönstermatchning med text. Till exempel avgör metoderna String.Contains, String.EndsWith och String.StartsWith om en stränginstans innehåller en angiven delsträng, och metoderna String.IndexOf, String.IndexOfAny, String.LastIndexOf och String.LastIndexOfAny returnerar startpositionen för en angiven delsträng i en sträng. Använd klassmetoderna System.String när du söker efter en specifik sträng. Regex Använd klassen när du söker efter ett specifikt mönster i en sträng. Mer information och exempel finns i Reguljära .NET-uttryck.

Statiska metoder jämfört med instansmetoder

När du har definierat ett mönster för reguljära uttryck kan du ange det för motorn för reguljära uttryck på något av två sätt:

  • Genom att instansiera ett Regex objekt som representerar det reguljära uttrycket. För att göra detta skickar du mönstret för reguljära uttryck till en Regex konstruktor. Ett Regex objekt är oföränderligt. När du instansierar ett Regex objekt med ett reguljärt uttryck kan objektets reguljära uttryck inte ändras.

  • Genom att ange både det reguljära uttrycket och texten för att söka efter en static (Shared i Visual Basic) Regex -metod. På så sätt kan du använda ett reguljärt uttryck utan att uttryckligen skapa ett Regex objekt.

Alla Regex metoder för mönsteridentifiering omfattar både statiska och instansöverbelastningar.

Motorn för reguljära uttryck måste kompilera ett visst mönster innan mönstret kan användas. Eftersom Regex objekt är oföränderliga är detta en engångsprocedur som inträffar när en Regex klasskonstruktor eller en statisk metod anropas. För att eliminera behovet av att upprepade gånger kompilera ett enda reguljärt uttryck cachelagrar motorn för reguljära uttryck de kompilerade reguljära uttryck som används i statiska metodanrop. Därför erbjuder mönstermatchningsmetoder för reguljära uttryck jämförbara prestanda för statiska metoder och instansmetoder. Cachelagring kan dock påverka prestanda negativt i följande två fall:

  • När du använder statiska metodanrop med ett stort antal reguljära uttryck. Som standard cachelagrar motorn för reguljära uttryck de 15 senast använda statiska reguljära uttrycken. Om programmet använder fler än 15 statiska reguljära uttryck måste vissa reguljära uttryck kompileras om. Om du vill förhindra den här omkompileringen kan du öka egenskapen Regex.CacheSize .

  • När du instansierar nya Regex objekt med reguljära uttryck som tidigare har kompilerats. Följande kod definierar till exempel ett reguljärt uttryck för att hitta duplicerade ord i en textström. Även om exemplet använder ett enda reguljärt uttryck instansierar det ett nytt Regex objekt för att bearbeta varje textrad. Detta resulterar i omkompilering av det reguljära uttrycket med varje iteration av loopen.

    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()
    

    För att förhindra omkompilering bör du instansiera ett enda Regex objekt som är tillgängligt för all kod som kräver det, enligt följande omskrivna exempel.

    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()
    

Utför reguljära uttrycksoperationer

Oavsett om du bestämmer dig för att instansiera ett Regex objekt och anropa dess metoder eller anropa statiska metoder, Regex erbjuder klassen följande mönstermatchningsfunktioner:

  • Validering av en match. Du anropar IsMatch metoden för att avgöra om en matchning finns.

  • Hämtning av en enskild matchning. Du anropar Match metoden för att hämta ett Match objekt som representerar den första matchningen i en sträng eller en del av en sträng. Efterföljande matchningar kan hämtas genom att anropa Match.NextMatch metoden.

  • Hämtning av alla matchningar. Du anropar Matches metoden för att hämta ett System.Text.RegularExpressions.MatchCollection objekt som representerar alla matchningar som finns i en sträng eller i en del av en sträng.

  • Ersättning av matchande text. Du anropar Replace metoden för att ersätta matchad text. Ersättningstexten kan också definieras med ett reguljärt uttryck. Dessutom innehåller några av Replace metoderna en MatchEvaluator parameter som gör att du kan definiera ersättningstexten programmatiskt.

  • Skapa en strängmatris som bildas från delar av en indatasträng. Du anropar Split metoden för att dela upp en indatasträng på positioner som definieras av det reguljära uttrycket.

Förutom dess mönstermatchningsmetoder Regex innehåller klassen flera specialmetoder:

  • Metoden Escape undflyr alla tecken som kan tolkas som reguljära uttrycksoperatorer i ett reguljärt uttryck eller en indatasträng.
  • Metoden Unescape tar bort dessa escape-tecken.
  • Metoden CompileToAssembly skapar en sammansättning som innehåller fördefinierade reguljära uttryck. .NET innehåller exempel på dessa specialsammansättningar i System.Web.RegularExpressions namnområdet.

Definiera ett timeout-värde

.NET har stöd för ett fullvärdigt reguljärt uttrycksspråk som ger stor kraft och flexibilitet i mönstermatchning. Kraften och flexibiliteten kommer dock till en kostnad: risken för dåliga prestanda. Reguljära uttryck som presterar dåligt är förvånansvärt enkla att skapa. I vissa fall kan reguljära uttrycksåtgärder som förlitar sig på överdriven bakåtspårning sluta svara när de bearbetar text som nästan matchar mönstret för reguljära uttryck. Mer information om .NET Regular Expression-motorn finns i Information om reguljärt uttrycksbeteende. Mer information om överdriven backtracking finns i Backtracking.

Från och med .NET Framework 4.5 kan du definiera ett tidsgränsintervall för matchningar av reguljära uttryck för att begränsa överdriven backtracking. Beroende på mönster för reguljära uttryck och indata kan körningstiden överskrida det angivna tidsgränsintervallet, men det kommer inte att ägna mer tid åt att backa tillbaka än det angivna tidsgränsintervallet. Om den reguljära uttrycksmotorn överskrider tidsgränsen utlöser den ett RegexMatchTimeoutException undantag. I de flesta fall förhindrar detta att motorn för reguljära uttryck slösar bort bearbetningskraft genom att försöka matcha text som nästan matchar mönstret för reguljära uttryck. Det kan dock också tyda på att tidsgränsintervallet har angetts för lågt eller att den aktuella datorbelastningen har orsakat en total försämring av prestandan.

Hur du hanterar undantaget beror på orsaken till undantaget. Om undantaget inträffar på grund av att tidsgränsintervallet har angetts för lågt eller på grund av överdriven maskinbelastning kan du öka tidsgränsintervallet och försöka matcha åtgärden igen. Om undantaget inträffar på grund av att det reguljära uttrycket förlitar sig på överdriven bakåtspårning kan du anta att det inte finns någon matchning, och om du vill kan du logga information som hjälper dig att ändra mönster för reguljära uttryck.

Du kan ange ett tidsgränsintervall genom att anropa Regex(String, RegexOptions, TimeSpan) konstruktorn när du instansierar ett reguljärt uttrycksobjekt. För statiska metoder kan du ange ett tidsgränsintervall genom att anropa en överlagring av en matchande metod som har en matchTimeout parameter. Om du inte uttryckligen anger ett timeout-värde bestäms standardvärdet för timeout enligt följande:

  • Med hjälp av tidsgränsvärdet för hela programmet, om det finns ett sådant. Ange tidsgränsvärdet för hela programmet genom att anropa AppDomain.SetData metoden för att tilldela strängrepresentationen av ett TimeSpan värde till REGEX_DEFAULT_MATCH_TIMEOUT egenskapen.
  • Genom att använda värdet InfiniteMatchTimeout, om inget timeout-värde för hela programmet har angetts.

Viktigt!

Vi rekommenderar att du anger ett timeout-värde i alla mönstermatchningsåtgärder för reguljära uttryck. Mer information finns i Metodtips för reguljära uttryck.

Exempel

I följande exempel används ett reguljärt uttryck för att söka efter upprepade förekomster av ord i en sträng. Det reguljära uttrycket \b(?<word>\w+)\s+(\k<word>)\b kan tolkas enligt följande tabell.

Mönster beskrivning
\b Starta matchningen vid en ordgräns.
(?<word>\w+) Matcha ett eller flera ordtecken upp till en ordgräns. Namnge den här fångade gruppen word.
\s+ Matcha ett eller flera mellanslagstecken.
(\k<word>) Matcha den insamlade gruppen med namnet word.
\b Hitta en ordgräns.
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

I nästa exempel visas användningen av ett reguljärt uttryck för att kontrollera om en sträng antingen representerar ett valutavärde eller har rätt format för att representera ett valutavärde. I det här fallet skapas det reguljära uttrycket dynamiskt från NumberFormatInfo.CurrencyDecimalSeparatoregenskaperna , CurrencyDecimalDigits, NumberFormatInfo.CurrencySymbol, NumberFormatInfo.NegativeSignoch NumberFormatInfo.PositiveSign för en-US-kulturen. Det resulterande reguljära uttrycket är ^\s*[\+-]?\s?\$?\s?(\d*\.?\d{2}?){1}$. Det här reguljära uttrycket kan tolkas enligt följande tabell.

Mönster beskrivning
^ Börja i början av strängen.
\s* Matcha noll eller fler blankstegstecken.
[\+-]? Matcha noll eller en förekomst av antingen det positiva tecknet eller det negativa tecknet.
\s? Matcha noll eller ett blankstegstecken.
\$? Matcha noll eller en förekomst av dollartecknet.
\s? Matcha noll eller ett blankstegstecken.
\d* Matcha noll eller fler decimalsiffror.
\.? Matcha noll eller ett decimaltecken.
(\d{2})? Samla in grupp 1: Matcha två decimalsiffror noll eller en gång.
(\d*\.?(\d{2})?){1} Matcha mönstret för heltals- och bråksiffror avgränsade med en decimaltecken exakt en gång.
$ Matcha slutet av strängen.

I det här fallet förutsätter det reguljära uttrycket att en giltig valutasträng inte innehåller gruppavgränsarsymboler och att den antingen inte har några bråktalssiffror eller antalet bråksiffror som definieras av den angivna kulturens CurrencyDecimalDigits egenskap.

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.

Eftersom det reguljära uttrycket i det här exemplet skapas dynamiskt vet du inte vid designtillfället om valutasymbolen, decimaltecknet eller positiva och negativa tecken på den angivna kulturen (en-US i det här exemplet) kan misstolkas av motorn för reguljära uttryck som operatorer för reguljärt uttrycksspråk. För att förhindra feltolkning skickar exemplet varje dynamiskt genererad sträng till Escape metoden.