C#从字符串中解析日期变量(例如%today-4days%, %now+15min%)

问题描述 投票:1回答:2

我有一个控制台应用程序,我经常需要传递变量DateTime's。 我目前使用的是一个开关,当变量与字符串完全匹配时返回值,并根据需要添加新的变量。 我想把它设计成能够解析变量并根据字符串执行正确的操作。

下面是我目前使用的几个格式的例子。

%today%
%today-5day%
%today-1sec%
%today+1month%
%now+15min%
%now-30sec%
%now+1week%

我还想解析变量,如

%lastmonday%
%nextfriday%
%monthstart%
%yearend% 

等,但这些似乎最好在开关中处理,如果不匹配,则传递给一个函数来解析和计算上面的例子。

我不知道有什么最优雅的方法来实现这一点,在我的搜索中无法找到很多。

c# parsing variables
2个回答
4
投票

你可以尝试 正则表达式 以便进行解析。首先,我们提取一个模型:由于命令的格式是

Start (zero or more Modifiers)

例如

%today-5day+3hour%

哪儿 todayStart-5day+3hourModifiers 我们要两个 模型

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

0
投票

这是一个解析包含今天和星期的字符串的小例子(以%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;
            }
© www.soinside.com 2019 - 2024. All rights reserved.