How to validate if a path (string) contains a date in a variable time format in C# .NET?
Problem statement:
- There is a path that contains a date in a specific format which is a configuration parameter. Say, "yyyy_MMM_d",
- I need to detect if the path contains such a date:
- if it does, change it to a new date.
- if it doesn't, append the new date to the path
- The existing date in the path could be any date, it's not always yesterday's or tomorrow's.
Attempted solution:
- Detect via Regex (in the example
\d{4}_[a-zA-Z]{3}_\d{1,2}
) the portion that resembles the date and validate it afterwards usingTryParseExact()
- This works for a constant format, but I'd need to write a format to regexp compiler to support when the parameter changes. This isn't really worth the effort.
So, any other solution? I think that if there's no better way than what I have, I could probably demand a regex parameter next to the date format para开发者_运维百科meter :-)
Split the string on the slash delimiters. In a while loop, have a check that determines if it is a valid datetime string. If not, go to the next piece. If you get through every piece, you have no date, so append one.
Note, I'm not a .net developer, and as such, this could be something horrible and nasty that should never see the light of day...
Why not store in config the regex and the corresponding format string for DateTime.ParseExact?
Sure, you'll have to put some effort into working out the correct values, but then it's just a matter of updating the config and it's done.
You'll still have a problem parsing the date time unless you either tell it the format or it happens to fit a standard format, anyway.
Edit: I hope you don't mind me kind of hijacking the question, but I was curious with regard the discussion of Regex vs. TryParseExact vs. Exception handling, so I did a little test. The code, below, parses the same filename 100,000 times to identify and convert an embedded date.
I made sure to run the code in release mode and without the debugger attached; exception handling when debugging with Visual Studio is a killer.
I found that the Regex vs. TryParseExact methods were very close. Unsurprisingly, as the number of levels in the path increased, the Regex method became a little more efficient, but still nothing in it. If the path doesn't include a date at all, the balance shifts a little further towards the Regex method, but not enough to make a significant difference.
Using the 'incorrect' way of relying on exception handling was rather different, though!
My timings for the code shown below were:
Using Regex:
Duration: 543.0543
Using TryParse:
Duration: 429.0429
Using Exceptions:
Duration: 11930.4865
Those times are in milliseconds. I was originally running 1 million iterations, but I got bored when doing the Exceptions run ;-)
The experiment illustrates that the Regex and TryParseExact methods are pretty comparable in terms of performance, but the TryParseExact method has the significant advantage that it does not need a regex defining or deriving. Without doubt, it's a good choice for this problem.
It also illustrates the overhead of processing an exception. That's no surprise, really, either as the process of unwinding the stack is potentially time complex and time consuming. The application spent 95% of its time handling the exceptions. It illustrates the argument well, that you shouldn't rely on handling exceptions to parse date - hence the existence of the TryParse... methods.
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;
}
}
}
精彩评论