我本质上是想读取一个xml文件.其中一个值具有后缀,例如" 30d
".这意味着'30天'.所以我试图将其转换为DateTime.Now.AddDays(30)
.要在XML中读取此字段,我决定使用枚举:
enum DurationType { Min = "m", Hours = "h", Days = "d" }
Run Code Online (Sandbox Code Playgroud)
现在我不确定如何有效地处理这个问题(当涉及枚举时我有点愚蠢).我应该首先将字符串中的后缀(在本例中为"d")分开,然后在enum
使用switch
语句中尝试匹配它吗?
我想如果你哑巴了我的问题,这将会是:什么是从,以获得最佳的方式30d
,来DateTime.Now.AddDays(30)
?
您可以创建一个ExtensionMethod来解析字符串并返回所需的DateTime
就像是:
public static DateTime AddDuration(this DateTime datetime, string str)
{
int value = 0;
int mutiplier = str.EndsWith("d") ? 1440 : str.EndsWith("h") ? 60 : 1;
if (int.TryParse(str.TrimEnd(new char[]{'m','h','d'}), out value))
{
return datetime.AddMinutes(value * mutiplier);
}
return datetime;
}
Run Code Online (Sandbox Code Playgroud)
用法:
var date = DateTime.Now.AddDuration("2d");
Run Code Online (Sandbox Code Playgroud)
这似乎是使用正则表达式的好地方; 特别是捕获组.
以下是一个工作示例:
using System;
using System.Text.RegularExpressions;
namespace RegexCaptureGroups
{
class Program
{
// Below is a breakdown of this regular expression:
// First, one or more digits followed by "d" or "D" to represent days.
// Second, one or more digits followed by "h" or "H" to represent hours.
// Third, one or more digits followed by "m" or "M" to represent minutes.
// Each component can be separated by any number of spaces, or none.
private static readonly Regex DurationRegex = new Regex(@"((?<Days>\d+)d)?\s*((?<Hours>\d+)h)?\s*((?<Minutes>\d+)m)?", RegexOptions.IgnoreCase);
public static TimeSpan ParseDuration(string input)
{
var match = DurationRegex.Match(input);
var days = match.Groups["Days"].Value;
var hours = match.Groups["Hours"].Value;
var minutes = match.Groups["Minutes"].Value;
int daysAsInt32, hoursAsInt32, minutesAsInt32;
if (!int.TryParse(days, out daysAsInt32))
daysAsInt32 = 0;
if (!int.TryParse(hours, out hoursAsInt32))
hoursAsInt32 = 0;
if (!int.TryParse(minutes, out minutesAsInt32))
minutesAsInt32 = 0;
return new TimeSpan(daysAsInt32, hoursAsInt32, minutesAsInt32, 0);
}
static void Main(string[] args)
{
Console.WriteLine(ParseDuration("30d"));
Console.WriteLine(ParseDuration("12h"));
Console.WriteLine(ParseDuration("20m"));
Console.WriteLine(ParseDuration("1d 12h"));
Console.WriteLine(ParseDuration("5d 30m"));
Console.WriteLine(ParseDuration("1d 12h 20m"));
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:下面是一个替代,稍微更精简的上述版本,虽然我不确定哪一个我更喜欢.我通常不喜欢过于密集的代码.我调整了正则表达式,每个数字都限制了10位数.这允许我安全地使用该int.Parse
函数,因为我知道输入包含至少一个数字且最多十个(除非它根本没有捕获,在这种情况下它将是空字符串:因此,目的是ParseInt32ZeroIfNullOrEmpty方法).
// Below is a breakdown of this regular expression:
// First, one to ten digits followed by "d" or "D" to represent days.
// Second, one to ten digits followed by "h" or "H" to represent hours.
// Third, one to ten digits followed by "m" or "M" to represent minutes.
// Each component can be separated by any number of spaces, or none.
private static readonly Regex DurationRegex = new Regex(@"((?<Days>\d{1,10})d)?\s*((?<Hours>\d{1,10})h)?\s*((?<Minutes>\d{1,10})m)?", RegexOptions.IgnoreCase);
private static int ParseInt32ZeroIfNullOrEmpty(string input)
{
return string.IsNullOrEmpty(input) ? 0 : int.Parse(input);
}
public static TimeSpan ParseDuration(string input)
{
var match = DurationRegex.Match(input);
return new TimeSpan(
ParseInt32ZeroIfNullOrEmpty(match.Groups["Days"].Value),
ParseInt32ZeroIfNullOrEmpty(match.Groups["Hours"].Value),
ParseInt32ZeroIfNullOrEmpty(match.Groups["Minutes"].Value),
0);
}
Run Code Online (Sandbox Code Playgroud)
编辑:为了更进一步,我在下面添加了另一个版本,它处理日,小时,分钟,秒和毫秒,每个版本都有各种缩写.为了便于阅读,我将正则表达式拆分为多行.注意,我还必须通过(\b|(?=[^a-z]))
在每个组件的末尾使用来调整表达式:这是因为"ms"单元被捕获为"m"单元.与"[^ az]"一起使用的"?="的特殊语法表示匹配字符但不"消耗"它.
// Below is a breakdown of this regular expression:
// First, one to ten digits followed by "d", "dy", "dys", "day", or "days".
// Second, one to ten digits followed by "h", "hr", "hrs", "hour", or "hours".
// Third, one to ten digits followed by "m", "min", "minute", or "minutes".
// Fourth, one to ten digits followed by "s", "sec", "second", or "seconds".
// Fifth, one to ten digits followed by "ms", "msec", "millisec", "millisecond", or "milliseconds".
// Each component may be separated by any number of spaces, or none.
// The expression is case-insensitive.
private static readonly Regex DurationRegex = new Regex(@"
((?<Days>\d{1,10})(d|dy|dys|day|days)(\b|(?=[^a-z])))?\s*
((?<Hours>\d{1,10})(h|hr|hrs|hour|hours)(\b|(?=[^a-z])))?\s*
((?<Minutes>\d{1,10})(m|min|minute|minutes)(\b|(?=[^a-z])))?\s*
((?<Seconds>\d{1,10})(s|sec|second|seconds)(\b|(?=[^a-z])))?\s*
((?<Milliseconds>\d{1,10})(ms|msec|millisec|millisecond|milliseconds)(\b|(?=[^a-z])))?",
RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
private static int ParseInt32ZeroIfNullOrEmpty(string input)
{
return string.IsNullOrEmpty(input) ? 0 : int.Parse(input);
}
public static TimeSpan ParseDuration(string input)
{
var match = DurationRegex.Match(input);
return new TimeSpan(
ParseInt32ZeroIfNullOrEmpty(match.Groups["Days"].Value),
ParseInt32ZeroIfNullOrEmpty(match.Groups["Hours"].Value),
ParseInt32ZeroIfNullOrEmpty(match.Groups["Minutes"].Value),
ParseInt32ZeroIfNullOrEmpty(match.Groups["Seconds"].Value),
ParseInt32ZeroIfNullOrEmpty(match.Groups["Milliseconds"].Value));
}
Run Code Online (Sandbox Code Playgroud)