System.Text.RegularExpressions.Regex クラス
この記事では、この API のリファレンス ドキュメントへの補足的な解説を提供します。
Regex クラスは .NET の正規表現エンジン。 このクラスを使用すると、次のことができます。
- 大量のテキストをすばやく解析して、特定の文字パターンを見つけます。
- テキスト部分文字列の抽出、編集、置換、または削除を行う
- 抽出した文字列をコレクションに追加して、レポートを生成します。
Note
文字列が特定の正規表現パターンに準拠しているかどうかを判断して検証する場合は、 System.Configuration.RegexStringValidator クラスを使用できます。
正規表現を使用するには、 Regular 式言語 - クイック リファレンスに記載されている構文を使用して、テキスト ストリームで識別するパターンを定義します。 次に、必要に応じて、 Regex オブジェクトをインスタンス化できます。 最後に、正規表現パターンに一致するテキストの置換やパターン一致の識別など、何らかの操作を実行するメソッドを呼び出します。
正規表現言語の詳細については、「 言語 - クイック リファレンス 次のいずれかのパンフレットをダウンロードして印刷する」を参照してください。
Word (.docx) 形式のクイック リファレンス PDF (.pdf) 形式のクイック リファレンス
Regex メソッドと String メソッド
System.String クラスには、テキストとのパターン マッチングを実行するために使用できるいくつかの検索および比較メソッドが含まれています。 たとえば、 String.Contains、 String.EndsWith、および String.StartsWith のメソッドは、文字列インスタンスに指定された部分文字列が含まれているかどうかを判断します。また、 String.IndexOf、 String.IndexOfAny、 String.LastIndexOf、および String.LastIndexOfAny メソッドは、文字列内の指定した部分文字列の開始位置を返します。 特定の文字列を検索するときは、 System.String クラスのメソッドを使用します。 文字列内の特定のパターンを検索するときは、 Regex クラスを使用します。 詳細と例については、「 .NET 正規表現」を参照してください。
静的メソッドとインスタンス メソッド
正規表現パターンを定義したら、次の 2 つの方法のいずれかで正規表現エンジンに提供できます。
正規表現を表す Regex オブジェクトをインスタンス化する。 これを行うには、正規表現パターンを Regex コンストラクターに渡します。 Regex オブジェクトは不変です。正規表現を使用してRegex オブジェクトをインスタンス化する場合、そのオブジェクトの正規表現を変更することはできません。
正規表現と検索するテキストの両方を
static
(Visual Basic のShared
) Regex メソッドに指定します。 これにより、 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.CurrencyDecimalSeparator、 CurrencyDecimalDigits、 NumberFormatInfo.CurrencySymbol、 NumberFormatInfo.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 メソッドに渡します。
.NET