System.Text.RegularExpressions.Regex クラス

この記事では、この API のリファレンス ドキュメントへの補足的な解説を提供します。

このクラスは Regex .NET の正規表現エンジン。 このクラスを使用すると、次のことができます。

  • 大量のテキストをすばやく解析して、特定の文字パターンを見つけます。
  • テキスト部分文字列の抽出、編集、置換、または削除を行う
  • 抽出した文字列をコレクションに追加して、レポートを生成します。

Note

文字列が特定の正規表現パターンに準拠しているかどうかを判断して検証する場合は、クラスを System.Configuration.RegexStringValidator 使用できます。

正規表現を使用するには、正規表現言語に記載されている構文 (クイック リファレンス) を使用して、テキスト ストリームで識別するパターンを定義します。 次に、必要に応じてオブジェクトを Regex インスタンス化できます。 最後に、正規表現パターンに一致するテキストの置換やパターン一致の識別など、何らかの操作を実行するメソッドを呼び出します。

正規表現言語の詳細については、「正規表現言語 - クイック リファレンス」を参照するか、次のいずれかのパンフレットをダウンロードして印刷します。

Word (.docx) 形式のクイック リファレンス (PDF (.pdf) 形式のクイック リファレンス

Regex メソッドと String メソッド

この System.String クラスには、テキストとのパターン マッチングを実行するために使用できるいくつかの検索および比較メソッドが含まれています。 たとえば、文字列String.StartsWithString.EndsWithインスタンスにString.Contains指定した部分文字列が含まれているかどうか、および 、String.IndexOfAnyString.LastIndexOf,、およびString.LastIndexOfAnyメソッドが文字列内の指定した部分文字列String.IndexOfの開始位置を返すかどうかを決定します。 特定の文字列を検索するときは、 System.String クラスのメソッドを使用します。 文字列内の特定の Regex パターンを検索する場合は、このクラスを使用します。 詳細と例については、「.NET 正規表現」を参照してください

静的メソッドとインスタンス メソッド

正規表現パターンを定義したら、次の 2 つの方法のいずれかで正規表現エンジンに提供できます。

  • 正規表現を Regex 表すオブジェクトをインスタンス化する。 これを行うには、正規表現パターンをコンストラクターに Regex 渡します。 Regexオブジェクトは不変です。正規表現を使用してオブジェクトをRegexインスタンス化する場合、そのオブジェクトの正規表現を変更することはできません。

  • 検索する正規表現とテキストの両方を (SharedVisual Basic の) Regex メソッドにstatic指定します。 これにより、オブジェクトを明示的に作成せずに正規表現を Regex 使用できます。

すべての Regex パターン識別メソッドには、静的オーバーロードとインスタンス オーバーロードの両方が含まれます。

正規表現エンジンは、パターンを使用する前に特定のパターンをコンパイルする必要があります。 オブジェクトは不変であるため Regex 、これはクラス コンストラクターまたは静的メソッドが呼び出されたときに Regex 発生する 1 回限りのプロシージャです。 正規表現エンジンは、単一の正規表現を繰り返しコンパイルする必要をなくすために、静的メソッド呼び出しで使用されるコンパイル済みの正規表現をキャッシュします。 その結果、正規表現パターン マッチング メソッドは、静的メソッドとインスタンス メソッドに対して同等のパフォーマンスを提供します。 ただし、キャッシュは、次の 2 つのケースでパフォーマンスに悪影響を与える可能性があります。

  • 多数の正規表現で静的メソッド呼び出しを使用する場合。 既定では、正規表現エンジンは、最近使用した 15 個の静的正規表現をキャッシュします。 アプリケーションで 15 を超える静的正規表現を使用している場合は、一部の正規表現を再コンパイルする必要があります。 この再コンパイルを回避するには、プロパティを Regex.CacheSize 増やします。

  • 以前にコンパイルされた正規表現を使用して新しい Regex オブジェクトをインスタンス化する場合。 たとえば、次のコードでは、テキスト ストリーム内の重複する単語を検索する正規表現を定義します。 この例では 1 つの正規表現を使用していますが、新しい Regex オブジェクトをインスタンス化してテキストの各行を処理します。 これにより、ループの反復ごとに正規表現が再コンパイルされます。

    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("{0} ({1} matches):", input, matches.Count);
          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()
    

    再コンパイルを防ぐには、次の書き換えられた例に示すように、必要なすべてのコードからアクセスできる 1 つの Regex オブジェクトをインスタンス化する必要があります。

    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("{0} ({1} matches):", input, matches.Count);
          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()
    

正規表現操作を実行する

オブジェクトをインスタンス化 Regex してそのメソッドを呼び出すか、静的メソッドを呼び出すかに関係なく、 Regex クラスは次のパターンマッチング機能を提供します。

  • 一致の検証。 このメソッドを IsMatch 呼び出して、一致するものが存在するかどうかを判断します。

  • 1 つの一致の取得。 メソッドを Match 呼び出して、 Match 文字列または文字列の一部で最初の一致を表すオブジェクトを取得します。 後続の一致は、メソッドを呼び出 Match.NextMatch すことによって取得できます。

  • すべての一致の取得。 このメソッドを Matches 呼び出して、 System.Text.RegularExpressions.MatchCollection 文字列または文字列の一部で検出されたすべての一致を表すオブジェクトを取得します。

  • 一致したテキストの置換。 一致したテキストを Replace 置き換えるメソッドを呼び出します。 置換テキストは正規表現で定義することもできます。 さらに、一部の Replace メソッドには、置換テキストをプログラムで定義できるパラメーターが含まれています MatchEvaluator

  • 入力文字列の一部から形成される文字列配列の作成。 メソッドを Split 呼び出して、正規表現で定義されている位置で入力文字列を分割します。

このクラスには、そのパターン マッチング メソッドに加えて、 Regex いくつかの特殊な目的のメソッドが含まれています。

  • このメソッドは Escape 、正規表現または入力文字列で正規表現演算子として解釈できる文字をエスケープします。
  • このメソッドは Unescape 、これらのエスケープ文字を削除します。
  • このメソッドは CompileToAssembly 、定義済みの正規表現を含むアセンブリを作成します。 .NET には、名前空間内のこれらの特殊な目的のアセンブリの例が System.Web.RegularExpressions 含まれています。

タイムアウト値を定義する

.NET では、フル機能の正規表現言語がサポートされており、パターン マッチングに大きなパワーと柔軟性を提供します。 ただし、パワーと柔軟性にはコストがかかります。パフォーマンスが低下するリスクがあります。 パフォーマンスが低い正規表現は、驚くほど簡単に作成できます。 場合によっては、過剰なバックトラッキングに依存する正規表現操作は、正規表現パターンにほぼ一致するテキストを処理するときに応答を停止するように見える場合があります。 .NET 正規表現エンジンの詳細については、「正規表現の動作の詳細」を参照してください。 過剰なバックトラッキングの詳細については、「バックトラッキング」を参照してください

.NET Framework 4.5 以降では、正規表現の一致のタイムアウト間隔を定義して、過剰なバックトラッキングを制限できます。 正規表現パターンと入力テキストによっては、実行時間が指定されたタイムアウト間隔を超える場合がありますが、指定されたタイムアウト間隔よりもバックトラッキングに時間がかかることがあります。 正規表現エンジンがタイムアウトすると、例外が RegexMatchTimeoutException スローされます。 ほとんどの場合、正規表現エンジンは正規表現パターンにほぼ一致するテキストと一致させることで、処理能力を無駄にすることを防ぎます。 ただし、タイムアウト間隔が低すぎるか、現在のマシンの負荷によってパフォーマンスが全体的に低下したことを示す場合もあります。

例外の処理方法は、例外の原因によって異なります。 タイムアウト間隔が低すぎるか、過剰なマシン負荷が原因で例外が発生した場合は、タイムアウト間隔を長くして、一致する操作を再試行できます。 正規表現が過剰なバックトラッキングに依存しているために例外が発生した場合は、一致が存在しないと想定できます。また、必要に応じて、正規表現パターンの変更に役立つ情報をログに記録できます。

正規表現オブジェクトをインスタンス化するときにコンストラクターを Regex(String, RegexOptions, TimeSpan) 呼び出すことで、タイムアウト間隔を設定できます。 静的メソッドの場合は、パラメーターを持つ一致するメソッドのオーバーロードを呼び出すことによって、タイムアウト間隔を matchTimeout 設定できます。 タイムアウト値を明示的に設定しない場合、既定のタイムアウト値は次のように決定されます。

  • 存在する場合は、アプリケーション全体のタイムアウト値を使用します。 メソッドを呼び出して値の文字列形式を AppDomain.SetData プロパティに割り当てることで、アプリケーション全体の TimeSpan タイムアウト値を REGEX_DEFAULT_MATCH_TIMEOUT 設定します。
  • アプリケーション全体のタイムアウト値が設定されていない場合は、値 InfiniteMatchTimeout を使用します。

重要

すべての正規表現パターンマッチング操作でタイムアウト値を設定することをお勧めします。 詳細については、「正規表現のベスト プラクティス」を参照してください

次の例では、正規表現を使用して、文字列内で繰り返し出現する単語をチェックします。 正規表現 \b(?<word>\w+)\s+(\k<word>)\b は、次の表に示すように解釈できます。

パターン 説明
\b 単語の境界で一致を開始します。
(?<word>\w+) 単語の境界まで 1 つ以上の単語文字と一致します。 このキャプチャ されたグループに名前を付けます word
\s+ 1 つ以上の空白文字と一致します。
(\k<word>) という名前 wordのキャプチャされたグループと一致します。
\b ワード境界に一致します。
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("{0} matches found in:\n   {1}",
                          matches.Count,
                          text);

        // Report on each match.
        foreach (Match match in matches)
        {
            GroupCollection groups = match.Groups;
            Console.WriteLine("'{0}' repeated at positions {1} and {2}",
                              groups["word"].Value,
                              groups[0].Index,
                              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

次の例は、正規表現を使用して、文字列が通貨値を表すか、通貨値を表す正しい形式を持つかをチェックする方法を示しています。 この場合、正規表現は en-US カルチャの NumberFormatInfo.CurrencyDecimalSeparatorCurrencyDecimalDigits、、 NumberFormatInfo.CurrencySymbolNumberFormatInfo.NegativeSign、および NumberFormatInfo.PositiveSign プロパティから動的に構築されます。 結果の正規表現は ^\s*[\+-]?\s?\$?\s?(\d*\.?\d{2}?){1}$. この正規表現は、次の表に示すように解釈できます。

パターン 説明
^ 文字列の先頭から開始します。
\s* 0 個以上の空白文字と一致します。
[\+-]? 0 個または 1 回の正符号または負符号のいずれかと一致します。
\s? 0 個または 1 個の空白文字と一致します。
\$? ドル記号の 0 回または 1 回の出現と一致します。
\s? 0 個または 1 個の空白文字と一致します。
\d* 0 個以上の 10 進数と一致します。
\.? 0 または 1 の小数点記号と一致します。
(\d{2})? キャプチャ グループ 1: 0 または 1 回の 2 桁の 10 進数と一致します。
(\d*\.?(\d{2})?){1} 小数点記号で区切られた整数と小数部のパターンに少なくとも 1 回一致します。
$ 文字列の末尾と一致します。

この場合、正規表現では、有効な通貨文字列にグループ区切り記号が含まれていないこと、および指定したカルチャ 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.

この例の正規表現は動的に構築されるため、指定したカルチャ (この例では en-US) の通貨記号、10 進記号、または正符号と負の符号が正規表現エンジンによって正規表現言語演算子として誤って解釈される可能性があるかどうかは、デザイン時にはわかりません。 誤った解釈を防ぐために、この例では動的に生成された各文字列をメソッドに Escape 渡します。