.NET 4.5 gives us improved control on the resolution of regular expressions so we can react when they don't resolve on time. This is extremely useful if we don't control the regular expressions/patterns, such as the ones provided by the users.
A badly formed pattern can have bad performance due to excessive backtracking and this new feature is really a lifesaver.
Next we are going to control the timeout in the regular expression, where we will react if the operation takes more than 1 millisecond:
caRegexTimeout
.using
clause for using regular expressions:Using System.Text.RegularExpressions;
Main
function:private static void ExecuteRegexExpression() { bool RegExIsMatch = false; string testString = "One Tile to rule them all, One Tile to find them… "; string RegExPattern = @"([a-z ]+)*!"; TimeSpantsRegexTimeout = TimeSpan.FromMilliseconds(1); try { RegExIsMatch = Regex.IsMatch(testString, RegExPattern, RegexOptions.None, tsRegexTimeout); } catch (RegexMatchTimeoutException ex) { Console.WriteLine("Timeout!!"); Console.WriteLine("- Timeout specified: " + ex.MatchTimeout); } catch (ArgumentOutOfRangeException ex) { Console.WriteLine("ArgumentOutOfRangeException!!"); Console.WriteLine(ex.Message); } Console.WriteLine("Finished succesfully: " + RegExIsMatch.ToString()); Console.ReadLine(); }
testString
and RegExPattern
to:String testString = "[email protected]"; String RegExPattern = @"^([w-.]+)@([w-.]+).[a-zA-Z]{2,4}$";
The RegEx.IsMatch()
method now accepts a parameter, which is matchTimeout
of type TimeSpan
, indicating the maximum time that we allow for the matching operation. If the execution time exceeds this amount, RegexMatchTimeoutException
is launched.
In our code, we have captured it with a try-catch statement to provide a custom message and of course to react upon a badly formed regex pattern taking too much time.
We have tested it with an expression that will take some more time to validate and we got the timeout. When we changed the expression to a good one with a better execution time, the timeout was not reached.
Additionally, we also watched out for the ArgumentOutOfRangeException
, which is thrown when TimeSpan
is zero, or negative, or greater than 24 days.
We could also set a global matchTimeout
for the application through the "REGEX_DEFAULT_MATCH_TIMEOUT"
property with the AppDomain
.SetData
method:
AppDomain.CurrentDomain.SetData("REGEX_DEFAULT_MATCH_TIMEOUT",TimeSpan.FromMilliseconds(200));
Anyway, if we specify the matchTimeout
parameter, we will override the global value.