Regexクラスでは正規表現エンジンの実行をタイムアウトさせることができます。 IsMatch・Replace等の静的メソッドでTimeSpanを指定するか、Regexインスタンスを作成する際にコンストラクタでTimeSpanを指定すると、その時間内にパターンマッチングが完了しない場合はタイムアウトしたとして例外をスローさせることができます。 タイムアウトした場合、例外としてRegexMatchTimeoutExceptionがスローされます。 正規表現エンジンのタイムアウトは.NET Framework 4.5以降で使用できます。
入力文字列が巨大な場合や、処理負荷の大きい正規表現を指定した場合などは、パターンマッチングの際にタイムアウトする可能性があります。 例えば次の正規表現は一見単純に見えますが、大量のバックトラッキングが発生するため、入力文字列の長さによってはタイムアウトします。 (タイムアウトしない場合は、入力文字列のa
の数を増やすとタイムアウトするようになります)
using System;
using System.Text.RegularExpressions;
class Sample {
static void Main()
{
// 0.1秒でタイムアウトする正規表現
var r = new Regex(@"^(a+)+$", RegexOptions.None, TimeSpan.FromSeconds(0.1));
try {
r.IsMatch("aaaaaaaaaaaaaaaaaaaaaa!");
}
catch (RegexMatchTimeoutException ex) {
Console.Error.WriteLine("入力文字列'{0}'に対する正規表現'{1}'のパターンマッチングがタイムアウトしました", ex.Input, ex.Pattern);
}
}
}
入力文字列'aaaaaaaaaaaaaaaaaaaaaa!'に対する正規表現'^(a+)+$'のパターンマッチングがタイムアウトしました
上記の例にもあるように、スローされた例外RegexMatchTimeoutExceptionのPatternプロパティを参照すると、タイムアウトした正規表現を取得することができ、同様にInputプロパティを参照するとタイムアウトの原因となった入力文字列を取得することができます。
デフォルトの状態(TimeSpanを指定しない場合)ではタイムアウトしません。 TimeSpanとしてRegex.InfiniteMatchTimeoutを指定すると、デフォルトの状態と同じになり、タイムアウトしないことを明示的に指定することができます。
なお、RegexコンストラクタでTimeSpanを設定した場合、設定したタイムアウト時間はRegex.MatchTimeoutプロパティを参照することで取得できます。