如何在C# .NET中验证路径(字符串)是否包含以可变时间格式表示的日期?

4
问题陈述:
有一个路径包含特定格式的日期,该格式是配置参数。比如说,“yyyy_MMM_d”,
我需要检测路径是否包含这样的日期:
如果包含,则更改为新日期。
如果不包含,则将新日期附加到路径中。
路径中现有的日期可能是任何日期,不一定是昨天或明天的日期。
尝试的解决方案:
通过正则表达式(在示例中为\d{4}_[a-zA-Z]{3}_\d{1,2})检测类似日期的部分,并使用TryParseExact()进行验证。
这对于固定格式有效,但是我需要编写一个格式到正则表达式的编译器来支持参数更改时的情况。这并不值得努力。
那么,有其他解决方案吗?如果没有比我拥有的更好的方法,我可能需要要求在日期格式参数旁边提供正则表达式参数 :-)
2个回答

1

在斜杠分隔符上拆分字符串。在while循环中,进行检查以确定其是否为有效的日期时间字符串。如果不是,则转到下一个片段。如果您处理完所有片段仍未找到日期,则添加一个日期。

请注意,我不是 .net 开发人员,因此这可能是一些可怕且不堪入目的东西...


1
好主意。我感到羞愧,没有自己想到它 :) - Vinko Vrsalovic
1
哎呀!无意冒犯。异常处理的成本很高,不应该作为解析数据的“大棒”方法来使用。 - Steve Morgan
DateTime.TryParseExact(在问题中已经提到)可以在使用此方法时防止异常抛出。 - Scott Munro
@Steve Morgan或许吧,但每个字符串大概不会很长。我尽量避免过早优化代码,所以除非我们担心这一部分的速度会受到影响,否则我认为这是一个可行的解决方案。 - Spencer Rathbun
我更新了我的答案-希望你不介意,并附上一个测试以说明不同方法之间的差异。 我坚信异常很昂贵(如果它们突然变得更快,我会感到惊讶-它们一直很慢!)。 但是TryParseExact方法肯定得到了认可。 - Steve Morgan
显示剩余7条评论

1

为什么不在配置文件中存储DateTime.ParseExact的正则表达式和相应的格式字符串呢?

当然,你需要花费一些精力来确定正确的值,但之后只需更新配置文件就可以了。

无论如何,除非您告诉它格式或它恰好符合标准格式,否则您仍将面临解析日期时间的问题。

编辑:希望您不介意我有点篡改问题,但我对Regex vs. TryParseExact vs.异常处理的讨论很感兴趣,所以我做了一个小测试。下面的代码将相同的文件名解析100,000次,以识别并转换嵌入的日期。

我确保在发布模式下运行代码,并且没有附加调试器;在使用Visual Studio进行调试时,异常处理会使程序变慢。

我发现Regex vs. TryParseExact方法非常接近。毫不奇怪,随着路径级数的增加,Regex方法变得更加高效,但仍然没有太大差别。如果路径根本不包含日期,则平衡略微向Regex方法倾斜,但不足以产生显着差异。

然而,使用依赖异常处理的“错误”方式却大不相同!

下面是我展示的代码的时间:

Using Regex:
Duration: 543.0543
Using TryParse:
Duration: 429.0429
Using Exceptions:
Duration: 11930.4865

这些时间是以毫秒为单位的。我最初运行了100万次迭代,但在执行异常运行时感到无聊。

实验表明,Regex和TryParseExact方法在性能方面相当可比,但TryParseExact方法具有显着优势,因为它不需要定义或派生正则表达式。毫无疑问,它是解决此问题的不错选择。

它还说明了处理异常的开销。这并不奇怪,因为展开堆栈的过程可能是时间复杂和耗时的。应用程序花费95%的时间来处理异常。这很好地说明了一个论点,即您不应该依赖于处理异常来解析日期-因此存在TryParse ...方法。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Globalization;

namespace ConsoleApplication1
{
    class Program
    {
        static Regex r = new Regex(@"\d{4}_[a-zA-Z]{3}_\d{1,2}");
        static string dateFormat = "yyyy_MMM_d";
        static CultureInfo provider = CultureInfo.InvariantCulture;

        static void Main(string[] args)
        {
            string filepath = @"C:\TopDir\SubDir\2011_JUL_26\filename.ext";

            DateTime startTime;
            DateTime endTime;
            TimeSpan duration;
            bool success;
            DateTime result;

            System.Console.WriteLine("Using Regex:");
            startTime = DateTime.Now;
            for (int ix = 0; ix < 100000; ix++)
            {
                success = UsingRegex(filepath, out result);
            }
            endTime = DateTime.Now;
            duration = endTime - startTime;
            System.Console.WriteLine("Duration: " + duration.TotalMilliseconds.ToString());

            System.Console.WriteLine("Using TryParse:");
            startTime = DateTime.Now;
            for (int ix = 0; ix < 100000; ix++)
            {
                success = UsingTryParse(filepath, out result);
            }
            endTime = DateTime.Now;
            duration = endTime - startTime;
            System.Console.WriteLine("Duration: " + duration.TotalMilliseconds.ToString());

            System.Console.WriteLine("Using Exceptions:");
            startTime = DateTime.Now;
            for (int ix = 0; ix < 100000; ix++)
            {
                success = UsingExceptions(filepath, out result);
            }
            endTime = DateTime.Now;
            duration = endTime - startTime;
            System.Console.WriteLine("Duration: " + duration.TotalMilliseconds.ToString());
        }

        static bool UsingRegex(string filepath, out DateTime result)
        {
            var matches = r.Matches(filepath);

            if (matches.Count > 0)
            {
                return DateTime.TryParseExact(matches[0].Value, dateFormat, 
                          provider, DateTimeStyles.None, out result);
            }

            result = DateTime.MinValue;
            return false;
        }

        static bool UsingTryParse(string filepath, out DateTime result)
        {
            var parts = filepath.Split('\\');

            foreach (var part in parts)
            {
                if( DateTime.TryParseExact(part, dateFormat, provider, 
                      DateTimeStyles.None, out result) )
                {
                    return true;
                }
            }

            result = DateTime.MinValue;
            return false;
        }

        static bool UsingExceptions(string filepath, out DateTime result)
        {
            var parts = filepath.Split('\\');

            foreach (var part in parts)
            {
                try
                {
                    result = DateTime.ParseExact(part, dateFormat, 
                                provider, DateTimeStyles.None);
                    return true;
                }
                catch(Exception ex)
                {
                }
            }

            result = DateTime.MinValue;
            return false;
        }
    }
}

如果可能的话,我宁愿让应用程序自己解决问题,而不是添加额外的配置参数。 - Vinko Vrsalovic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接