我有一个控制台应用程序,我经常需要传递变量DateTime's。 我目前使用的是一个开关,当变量与字符串完全匹配时返回值,并根据需要添加新的变量。 我想把它设计成能够解析变量并根据字符串执行正确的操作。
下面是我目前使用的几个格式的例子。
%today%
%today-5day%
%today-1sec%
%today+1month%
%now+15min%
%now-30sec%
%now+1week%
我还想解析变量,如
%lastmonday%
%nextfriday%
%monthstart%
%yearend%
等,但这些似乎最好在开关中处理,如果不匹配,则传递给一个函数来解析和计算上面的例子。
我不知道有什么最优雅的方法来实现这一点,在我的搜索中无法找到很多。
你可以尝试 正则表达式 以便进行解析。首先,我们提取一个模型:由于命令的格式是
Start (zero or more Modifiers)
例如
%today-5day+3hour%
哪儿 today
是 Start
和 -5day
和 +3hour
是 Modifiers
我们要两个 模型
using System.Linq;
using System.Text.RegularExpressions;
...
//TODO: add more starting points here
private static Dictionary<string, Func<DateTime>> s_Starts =
new Dictionary<string, Func<DateTime>>(StringComparer.OrdinalIgnoreCase) {
{ "now", () => DateTime.Now},
{ "today", () => DateTime.Today},
{ "yearend", () => new DateTime(DateTime.Today.Year, 12, 31) },
};
//TODO: add more modifiers here
private static Dictionary<string, Func<DateTime, int, DateTime>> s_Modifiers =
new Dictionary<string, Func<DateTime, int, DateTime>>(StringComparer.OrdinalIgnoreCase) {
{ "month", (source, x) => source.AddMonths(x)},
{ "week", (source, x) => source.AddDays(x * 7)},
{ "day", (source, x) => source.AddDays(x)},
{ "hour", (source, x) => source.AddHours(x)},
{ "min", (source, x) => source.AddMinutes(x)},
{ "sec", (source, x) => source.AddSeconds(x)},
};
有了一个模型(以上两个字典),我们可以实施 MyParse
常规。
private static DateTime MyParse(string value) {
if (null == value)
throw new ArgumentNullException(nameof(value));
var match = Regex.Match(value,
@"^%(?<start>[a-zA-Z]+)(?<modify>\s*[+-]\s*[0-9]+\s*[a-zA-Z]+)*%$");
if (!match.Success)
throw new FormatException("Invalid format");
string start = match.Groups["start"].Value;
DateTime result = s_Starts.TryGetValue(start, out var startFunc)
? startFunc()
: throw new FormatException($"Start Date(Time) {start} is unknown.");
var adds = Regex
.Matches(match.Groups["modify"].Value, @"([+\-])\s*([0-9]+)\s*([a-zA-Z]+)")
.Cast<Match>()
.Select(m => (kind : m.Groups[3].Value,
amount : int.Parse(m.Groups[1].Value + m.Groups[2].Value)));
foreach (var (kind, amount) in adds)
if (s_Modifiers.TryGetValue(kind, out var func))
result = func(result, amount);
else
throw new FormatException($"Modification {kind} is unknown.");
return result;
}
演示:
string[] tests = new string[] {
"%today%",
"%today-5day%",
"%today-1sec%",
"%today+1month%",
"%now+15min%",
"%now-30sec%",
"%now+1week%",
};
string report = string.Join(Environment.NewLine, tests
.Select(test => $"{test,-15} :: {MyParse(test):dd MM yyyy HH:mm:ss}")
);
Console.Write(report);
结果:
%today% :: 07 05 2020 00:00:00
%today-5day% :: 02 05 2020 00:00:00
%today-1sec% :: 06 05 2020 23:59:59
%today+1month% :: 07 06 2020 00:00:00
%now+15min% :: 07 05 2020 18:34:55
%now-30sec% :: 07 05 2020 18:19:25
%now+1week% :: 14 05 2020 18:19:55
这是一个解析包含今天和星期的字符串的小例子(以%today-5day%为例)。
注意:只有当传递进来的添加天数的值在0-9之间时,这才会有效,要处理大的数字,你将不得不循环处理字符串的结果。
你也可以按照这个代码块来解析其他结果。
switch (date)
{
case var a when a.Contains("day") && a.Contains("today"):
return DateTime.Today.AddDays(char.GetNumericValue(date[date.Length - 5]));
default:
return DateTime.Today;
}