哪个更快:DateTime.TryParse或Regex

vd2z7a6w  于 2023-05-30  发布在  其他
关注(0)|答案(6)|浏览(87)

在.NET中,确定提供的字符串是否是日期,哪一个更快:使用DateTime将其转换为日期,还是使用正则表达式检查字符串作为日期的有效性?
我只需要确保提供的值是一个日期,之后我不会对它做任何事情。
谢谢。

qnakjoqk

qnakjoqk1#

我的第一个问题是哪一个更有表现力?还是哪个最有可读性?在这种情况下,性能的提高可能是微不足道的,我会投票给最容易维护/阅读的代码。

编辑

找到一个体面的,类似的职位。值得一读
Regex vs Tryparse what is the best in performance

oxf4rvwz

oxf4rvwz2#

一个好的正则表达式应该快得多,并且可能消耗更少的瞬时内存。
但硬币的另一面是:
您非常依赖于一种时间格式,这意味着国际化将是痛苦的,并且您的用户需要接受教育,以正确的格式输入日期。
此外,您将丢失一些日期验证,例如,如何在非闰年中清除2月29日?4月31日

h7appiyu

h7appiyu3#

最好的办法是为这两个代码都写一点测试代码,然后运行一个循环来执行一百万次。在不知道输入的情况下,很难回答这个问题(尽管我猜TryParse会更快)。
也就是说,今天的处理器上的时差可能无关紧要。

czq61nw1

czq61nw14#

更新:当run in a fiddle TryParse是一个 * 很多 * 快。
我对10000个项目进行了初步测试。看起来Regexp的速度至少是DateTime.Parse的两倍。使用下面的代码自己看看:

private string[] arrDates = new string[10000];

    protected void Page_Load(object sender, EventArgs e)
    {
        initialise();

        RunRegexDemo();
        RunDateTimeParseDemo();

    }

    private void initialise()
    {
        Random ryear, rmonth, rdate;
        ryear = new Random();
        rmonth = new Random();
        rdate = new Random();
        int y, m, d;

        DateTime dt;

        for (int i = 0; i < arrDates.Length; i++)
        {
            y = 0;
            m = 0;
            d = 0;

            while (y < 1850)
            {
                y = ryear.Next(2050);
            }
            while (m < 1 || m > 12)
            {
                m = rmonth.Next(12);
            }
            while (d < 1 || d > 28)
            {
                d = rdate.Next(28);
            }

            dt = new DateTime(y, m, d);

            arrDates[i] = dt.ToString("yyyy-MM-dd");

            //lbl1.Text += "<br />" + arrDates[i];
        }

    }

    private void RunRegexDemo()
    {
        System.Diagnostics.Stopwatch st = new System.Diagnostics.Stopwatch();
        lbl1.Text+= "<h4>Starting Regex demo</h4>";
        string f;

        st.Start();

        foreach(string x in arrDates){
            f= "<br/>" + x + " is a valid date? = " + System.Text.RegularExpressions.Regex.IsMatch(x, @"^(19|20)\d\d[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])$");
        }

        st.Stop();
        lbl1.Text+= "<p>Ended RegEx demo. Elapsed time: " + st.ElapsedMilliseconds;
    }

    protected void RunDateTimeParseDemo(){
        System.Diagnostics.Stopwatch st = new System.Diagnostics.Stopwatch();
        lbl1.Text += "<h4>Starting DateTime.Parse demo</h4>";
        st.Start();
        DateTime dt;
        string f;
        foreach (string x in arrDates)
        {
            f = "<br/>" + x + " is a valid date? = " + DateTime.TryParse(x, out dt);
        }

        st.Stop();
        lbl1.Text += "<p>Ended TryParse demo. Elapsed time: " + st.ElapsedMilliseconds;
    }
jyztefdp

jyztefdp5#

在这种情况下,Regex似乎更快,因为Regex只会查找模式,而DateTime parse需要找到模式并从该模式中获取值以创建DateTime对象

scyqe7ek

scyqe7ek6#

添加基准测试,比较以ISO 8601格式解析日期/时间的不同方法:

  • 使用自定义格式解析精确
  • ParseExact使用标准格式
  • 带有日期/时间创建的预编译正则表达式
  • 预编译的正则表达式只验证输入字符串的格式

底线是:

  • Regex在不创建日期/时间的情况下检查格式要快得多,并且不分配
  • 正则表达式解析和构建日期/时间的速度更慢,分配的数据也更多(并且需要更多的代码……)
  • 标准格式似乎分配较少
// * Summary *
    
    BenchmarkDotNet=v0.13.5, OS=Windows 10 (10.0.19044.2965/21H2/November2021Update)
    12th Gen Intel Core i9-12900H, 1 CPU, 20 logical and 14 physical cores
    .NET SDK=7.0.302
      [Host]   : .NET 7.0.5 (7.0.523.17405), X64 RyuJIT AVX2
      .NET 7.0 : .NET 7.0.5 (7.0.523.17405), X64 RyuJIT AVX2
    
    Job=.NET 7.0  Runtime=.NET 7.0

| 方法|循环|平均值|错误|标准差|比率|比率SD| Gen0|已分配|
| - -----|- -----|- -----|- -----|- -----|- -----|- -----|- -----|- -----|
| ParseExactCustomFormat|十个|277.65纳秒|3.148纳秒|2.791纳秒|一点|零点|0.0114| B|
| 解析精确标准格式|十个|254.07纳秒|0.490 ns| 0.435 ns|零点九二|零点零一|零点零零五|B|
| Regex|十个|423.21纳秒|4.026纳秒|3.766纳秒|一点五二|零点零二|0.0858|小行星1080 B|
| RegexIsMatch|十个|62.19纳秒|0.322纳秒|0.302纳秒|零点二二|零点|- ----|- ----|
| | | | | | | | | |
| ParseExactCustomFormat|一百|255.08纳秒|1.176纳秒|1.042纳秒|一点|零点|0.0114| B|
| 解析精确标准格式|一百|255.18纳秒|1.358纳秒|1.271纳秒|一点|零点零一|零点零零五|B|
| Regex|一百|427.15纳秒|8.149纳秒|7.224纳秒|一点六七|零点零三|0.0858|小行星1080 B|
| RegexIsMatch|一百|88.23纳秒|1.920 ns| 5.508纳秒|零点三二|零点零五|- ----|- ----|
| | | | | | | | | |
| ParseExactCustomFormat|一千|255.65纳秒|1.409纳秒|1.249纳秒|一点|零点|0.0114| B|
| 解析精确标准格式|一千|255.34纳秒|0.689纳秒|0.611 ns|一点|零点|零点零零五|B|
| Regex|一千|437.88纳秒|4.192纳秒|3.273纳秒|一点七一|零点零二|0.0858|小行星1080 B|
| RegexIsMatch|一千|62.69纳秒|0.744纳秒|0.696纳秒|零点二五|零点|- ----|- ----|

/// <summary>
/// Compares different methods of parsing a date/time in the ISO 8601 format.
/// </summary>
[SimpleJob(RuntimeMoniker.Net70)]
[MemoryDiagnoser]
public partial class DateTimeParseExactVsRegex
{
    [Params(10, 100, 1_000)]
    public int Loops { get; set; }

    /// <summary>
    /// Parses the input string by using <see cref="DateTime.ParseExact"/> 
    /// with a custom format.
    /// </summary>
    [Benchmark(Baseline = true)]
    public void ParseExactCustomFormat()
    {
        DateTime.ParseExact(_serializedDateTime, "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffffffK",
            CultureInfo.InvariantCulture,
            DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);
    }

    private const string _serializedDateTime = "2002-08-11T10:11:12.0000000Z";

    /// <summary>
    /// Parses the input string by using <see cref="DateTime.ParseExact"/> 
    /// with a standard format.
    /// </summary>
    [Benchmark]
    public void ParseExactStandardFormat()
    {
        DateTime.ParseExact(_serializedDateTime, "O",
            CultureInfo.InvariantCulture,
            DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);
    }

    /// <summary>
    /// Parses the input string by using a <see cref="Regex"/>.
    /// </summary>
    [Benchmark]
    public void Regex()
    {
        Match match = GetRegex().Match(_serializedDateTime);
        if (!match.Success)
        {
            throw new NotImplementedException();
        }

        int GetInt(string groupName)
        {
            ReadOnlySpan<char> yearAsString = match.Groups[groupName].ValueSpan;
            return int.Parse(yearAsString);
        }

        int year = GetInt("year"), month = GetInt("month"), day = GetInt("day");
        int hour = GetInt("hour"), minute = GetInt("minute"), second = GetInt("second");
        int subSecond = GetInt("subsecond");

        DateTime _ = new DateTime(year, month, day, hour, minute, second).AddTicks(subSecond);
    }

    [GeneratedRegex(@"^(?<year>\d{4})\-(?<month>\d{2})\-(?<day>\d{2})T(?<hour>\d{2})\:(?<minute>\d{2})\:(?<second>\d{2})\.(?<subsecond>\d{7})Z$")]
    private static partial System.Text.RegularExpressions.Regex GetRegex();

    /// <summary>
    /// Detects whether the input string matches the date/time format by using a <see cref="Regex"/>.
    /// </summary>
    [Benchmark]
    public void RegexIsMatch() => GetRegex().IsMatch(_serializedDateTime);
}

相关问题