c# - How to specify a timeout value in a source-compiled Regex? - Stack Overflow

admin2025-04-26  4

MS Learn suggests to use source-compiled Regex whenever possible. It is also best practice to use a timeout value when processing untrusted input. As far as I can tell, it is not possible to specify a timeout value for source-compiled regex. I have defined the regex

[GeneratedRegex(@"^[0-9A-Z]([-.\w]*[0-9A-Z])*$", RegexOptions.IgnoreCase)]
private static partial Regex Pattern();

// to prevent instantiation inside the loop
private static readonly Regex SCPattern = Pattern();

and want to parse an email address as in this example with Match m = SCPattern.Match(input). How do I specify a timeout value here?

Here is an MVP:

using System.Diagnostics;
using System.Text.RegularExpressions;

public partial class Program
{
    [GeneratedRegex(@"^[0-9A-Z]([-.\w]*[0-9A-Z])*$", RegexOptions.IgnoreCase)]
    private static partial Regex Pattern();

    // to prevent instantiation inside the loop
    private static readonly Regex SCPattern = Pattern();

    public static void Main()
    {
        Stopwatch sw;
        string[] addresses = { //"[email protected]",
                             "[email protected]" };
        // The following regular expression should not actually be used to
        // validate an email address.
        string pattern = @"^[0-9A-Z]([-.\w]*[0-9A-Z])*$";
        string pattern2 = @"^[0-9A-Z]([-.\w]*[0-9A-Z])*$"; // use a different pattern name to avoid caching
        string input;

        foreach (var address in addresses)
        {
            string mailBox = address[..address.IndexOf('@')];
            int index = 0;

            // try with regular regex
            Console.WriteLine("regular regex:");
            for (int ctr = mailBox.Length - 1; ctr >= 0; ctr--)
            {
                index++;

                input = mailBox.Substring(ctr, index);

                sw = Stopwatch.StartNew();
                Match m = Regex.Match(input, pattern, RegexOptions.IgnoreCase); //, TimeSpan.FromMilliseconds(100)
                sw.Stop();
                if (m.Success)
                    Console.WriteLine("{0,2}. Matched '{1,27}' in {2}",
                                      index, m.Value, sw.Elapsed);
                else
                    Console.WriteLine("{0,2}. Failed  '{1,27}' in {2}",
                                      index, input, sw.Elapsed);
            }
            Console.WriteLine();


            // try with precompiled regex
            index = 0;
            Console.WriteLine("precompiled regex:");
            for (int ctr = mailBox.Length - 1; ctr >= 0; ctr--)
            {
                index++;

                input = mailBox.Substring(ctr, index);

                sw = Stopwatch.StartNew();
                Match m = Regex.Match(input, pattern2, RegexOptions.Compiled | RegexOptions.IgnoreCase); // , TimeSpan.FromMilliseconds(100)
                sw.Stop();
                if (m.Success)
                    Console.WriteLine("{0,2}. Matched '{1,27}' in {2}",
                                      index, m.Value, sw.Elapsed);
                else
                    Console.WriteLine("{0,2}. Failed  '{1,27}' in {2}",
                                      index, input, sw.Elapsed);
            }
            Console.WriteLine();


            // try with source-compiled regex
            index = 0;
            Console.WriteLine("with source-compiled regex:");
            for (int ctr = mailBox.Length - 1; ctr >= 0; ctr--)
            {
                index++;

                input = mailBox.Substring(ctr, index);

                sw = Stopwatch.StartNew();
                Match m = SCPattern.Match(input); // does not work: , TimeSpan.FromMilliseconds(100)
                sw.Stop();
                if (m.Success)
                    Console.WriteLine("{0,2}. Matched '{1,27}' in {2}",
                                      index, m.Value, sw.Elapsed);
                else
                    Console.WriteLine("{0,2}. Failed  '{1,27}' in {2}",
                                      index, input, sw.Elapsed);
            }
        }

        Console.WriteLine("Press any key ...");
        Console.ReadKey();
    }
}

MS Learn suggests to use source-compiled Regex whenever possible. It is also best practice to use a timeout value when processing untrusted input. As far as I can tell, it is not possible to specify a timeout value for source-compiled regex. I have defined the regex

[GeneratedRegex(@"^[0-9A-Z]([-.\w]*[0-9A-Z])*$", RegexOptions.IgnoreCase)]
private static partial Regex Pattern();

// to prevent instantiation inside the loop
private static readonly Regex SCPattern = Pattern();

and want to parse an email address as in this example with Match m = SCPattern.Match(input). How do I specify a timeout value here?

Here is an MVP:

using System.Diagnostics;
using System.Text.RegularExpressions;

public partial class Program
{
    [GeneratedRegex(@"^[0-9A-Z]([-.\w]*[0-9A-Z])*$", RegexOptions.IgnoreCase)]
    private static partial Regex Pattern();

    // to prevent instantiation inside the loop
    private static readonly Regex SCPattern = Pattern();

    public static void Main()
    {
        Stopwatch sw;
        string[] addresses = { //"[email protected]",
                             "[email protected]" };
        // The following regular expression should not actually be used to
        // validate an email address.
        string pattern = @"^[0-9A-Z]([-.\w]*[0-9A-Z])*$";
        string pattern2 = @"^[0-9A-Z]([-.\w]*[0-9A-Z])*$"; // use a different pattern name to avoid caching
        string input;

        foreach (var address in addresses)
        {
            string mailBox = address[..address.IndexOf('@')];
            int index = 0;

            // try with regular regex
            Console.WriteLine("regular regex:");
            for (int ctr = mailBox.Length - 1; ctr >= 0; ctr--)
            {
                index++;

                input = mailBox.Substring(ctr, index);

                sw = Stopwatch.StartNew();
                Match m = Regex.Match(input, pattern, RegexOptions.IgnoreCase); //, TimeSpan.FromMilliseconds(100)
                sw.Stop();
                if (m.Success)
                    Console.WriteLine("{0,2}. Matched '{1,27}' in {2}",
                                      index, m.Value, sw.Elapsed);
                else
                    Console.WriteLine("{0,2}. Failed  '{1,27}' in {2}",
                                      index, input, sw.Elapsed);
            }
            Console.WriteLine();


            // try with precompiled regex
            index = 0;
            Console.WriteLine("precompiled regex:");
            for (int ctr = mailBox.Length - 1; ctr >= 0; ctr--)
            {
                index++;

                input = mailBox.Substring(ctr, index);

                sw = Stopwatch.StartNew();
                Match m = Regex.Match(input, pattern2, RegexOptions.Compiled | RegexOptions.IgnoreCase); // , TimeSpan.FromMilliseconds(100)
                sw.Stop();
                if (m.Success)
                    Console.WriteLine("{0,2}. Matched '{1,27}' in {2}",
                                      index, m.Value, sw.Elapsed);
                else
                    Console.WriteLine("{0,2}. Failed  '{1,27}' in {2}",
                                      index, input, sw.Elapsed);
            }
            Console.WriteLine();


            // try with source-compiled regex
            index = 0;
            Console.WriteLine("with source-compiled regex:");
            for (int ctr = mailBox.Length - 1; ctr >= 0; ctr--)
            {
                index++;

                input = mailBox.Substring(ctr, index);

                sw = Stopwatch.StartNew();
                Match m = SCPattern.Match(input); // does not work: , TimeSpan.FromMilliseconds(100)
                sw.Stop();
                if (m.Success)
                    Console.WriteLine("{0,2}. Matched '{1,27}' in {2}",
                                      index, m.Value, sw.Elapsed);
                else
                    Console.WriteLine("{0,2}. Failed  '{1,27}' in {2}",
                                      index, input, sw.Elapsed);
            }
        }

        Console.WriteLine("Press any key ...");
        Console.ReadKey();
    }
}
Share Improve this question asked Jan 13 at 9:28 QrtQrt 5595 silver badges21 bronze badges 3
  • FWIW : EmailAddressAttribute – Thomas Ayoub Commented Jan 13 at 16:56
  • Can it cause harm to validate email addresses with a regex? – Magnus Commented Jan 14 at 13:03
  • Also don't use backtracking as well (whenever you can). – greenoldman Commented Jan 15 at 6:01
Add a comment  | 

1 Answer 1

Reset to default 4

The GeneratedRegexAttribute has a constructor that accepts matchTimeoutMilliseconds, you can just use that like

[GeneratedRegex("...", RegexOptions.IgnoreCase, 1000 /* Or whatever value */)]
private static partial Regex Pattern();
转载请注明原文地址:http://anycun.com/QandA/1745658972a91059.html