【问题标题】:Is there a way to find the first string that matches a DateTime format string?有没有办法找到与 DateTime 格式字符串匹配的第一个字符串?
【发布时间】:2013-07-05 06:07:39
【问题描述】:

给定一个日期时间格式字符串,是否有一种标准方法可以找到与该格式匹配的第一个匹配子字符串?

例如,给定...

d-MMM-yy H:mm:ss

还有一些文字...

"blah 1 2 3 7-Jul-13 6:15:00 4 5 6 blah"

我希望它会返回

"7-Jul-13 6:15:00"

现在我可以通过解析找到这个字符串,但我想知道是否有任何库支持这样做?

【问题讨论】:

  • 它可能不是,但是,它确实意味着如果您想找到与日期时间格式匹配的字符串,您必须至少部分重新发明内置的格式约定。
  • @KeithNicholas 我不认为有一个库可以做到这一点,但你肯定可以尝试正则表达式 (\d{,2}-\w{3}-\d{,4}\s\d{,2}:\d{,2}:\d{,2}),我相信这将是这里的方式,或者你可以尝试拆分您拥有和使用索引的术语
  • @Prix 我只举了一个例子,但问题确实询问了日期时间格式字符串,它可以是任何有效的日期时间格式字符串。
  • @KeithNicholas 以您的示例和模式为例,例如 7 月 17 日会失败,2013 年也会失败,所以如果您有一组给定的可能性,您还可以制作一组您可以使用的正则表达式.
  • @Prix, 17 将通过,因为 'd' 表示 1 或 2 位数字,如果是 dd 则必须是 07-Jul... 假设您事先不知道哪个日期时间你得到的格式字符串。它是在运行时给出的。只要它的格式字符串有效。

标签: c# .net datetime-format datetime-parsing


【解决方案1】:

你可以试试NodaTime:

var input = "blah 1 2 3 7-Jul-13 6:15:00 4 5 6 blah";
var pattern = "d-MMM-yy H:mm:ss";
var nodaPattern = NodaTime.Text
    .LocalDateTimePattern
    .Create(pattern, System.Globalization.CultureInfo.CurrentUICulture);
for (int i = 0; i < input.Length - pattern.Length; i++)
{
    var result = nodaPattern.Parse(input.Substring(i, pattern.Length));
    if (result.Success)
    {
        Console.WriteLine(result.Value);
        break;
    }
}

【讨论】:

  • 可能你应该在循环之外创建模式实例以获得更好的性能。
  • 非常好。看起来很棒!
【解决方案2】:

可能是这样的:

通过解析文本中的每个单词找到格式字符串的每一部分,然后将两者结合起来创建日期时间

string test = "blah 1 2 3 7-Jul-13 6:15:00  4 5 6 blah";

int formatPart = 0;
bool dateFound = false;
string format = "d-MMM-yy H:mm:ss";
DateTime myDateTime = DateTime.MinValue;
foreach (var item in test.Split(' '))
{
    DateTime dummy;
    if (DateTime.TryParseExact(item, format.Split(' ')[formatPart], null, DateTimeStyles.NoCurrentDateDefault, out dummy))
    {
        if (myDateTime == DateTime.MinValue)
        {
            formatPart++;
            myDateTime = dummy;
            dateFound = myDateTime.Date != DateTime.MinValue.Date;
            continue;
        }

        // If date was found first, add time, else add date
        myDateTime = dateFound
         ? myDateTime.Add(new TimeSpan(dummy.Hour, dummy.Minute, dummy.Second))
         : dummy.Add(new TimeSpan(myDateTime.Hour, myDateTime.Minute, myDateTime.Second));
        break;
    }
}

测试:

Input: "blah 1 2 3 7-Jul-13 6:15:00  4 5 6 blah"
Format: "d-MMM-yy H:mm:ss"

Input: "blah 1 2 3 6:15:00 7-Jul-13 4 5 6 blah"
Format: "H:mm:ss d-MMM-yy"

Input: "blah 1 2 3 6:15:00 7-7-2013 4 5 6 blah"
Format: "H:mm:ss d-M-yyyy"

Input: "blah 1 2 3 07-07-2013 6:15:00  4 5 6 blah"
Format: "dd-MM-yyyy H:mm:ss" 

【讨论】:

    【解决方案3】:

    你可以试试这个:

    string original = "blah 1 2 3 7-jul-13 6:15:00 4 5 6 blah";
    Match mc = Regex.Match(original, @"\s*(?<date>\d+[-/][A-Z]{3}[-/]\d+)\s*([01]?[0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]", RegexOptions.IgnoreCase);
    
    if (mc.Success)
    {
        string datetime = mc.Groups[0].Value;
    }
    

    【讨论】:

      【解决方案4】:

      这可能不是最有效的,但它似乎是一个有趣的问题,所以我想我会尝试这种方法。

      它获取您的 DateTime 格式字符串,并通过将任何字母替换为 . 并将空格替换为 \\s 来生成正则表达式字符串模式。然后它根据该模式创建一个 Regex 对象,并尝试在输入句子中找到第一个匹配项。

      该匹配项(如果存在)然后传递给DateTime.TryParseExact 调用。我确信可以进行改进,但这可能有助于对不需要硬编码正则表达式或输入句子格式的技术提供一个总体思路。

      string inputSentence = "blah 1 2 3 7-Jul-13 6:15:00 4 5 6 blah";
      
      string dtformat = "d-MMM-yy H:mm:ss";
      
      //convert dtformat into regex pattern
      StringBuilder sb = new StringBuilder();
      foreach (char c in dtformat)
      {
          if (Char.IsLetter(c))
          {
             if (char.ToUpperInvariant(c) == 'D' || char.ToUpperInvariant(c) == 'H' || char.ToUpperInvariant(c) == 'S')            
                sb.Append(".{1,2}");
             else
                sb.Append(".");
          }
          else if(Char.IsWhiteSpace(c))        
             sb.Append("\\s");
          else
             sb.Append(c);
      }
      
      
      string dtPattern = sb.ToString();
      
      Regex dtrx = new Regex(dtPattern);
      
      //get the match using the regex pattern
      var dtMatch = dtrx.Match(inputSentence);
      
      if(dtMatch != null)
      {
          string firstString = dtMatch.Value.Trim();
      
          //try and parse the datetime from the string
          DateTime firstMatch;
          if (DateTime.TryParseExact(dstr, dtformat, null, DateTimeStyles.None, out firstMatch))
          {
             Console.WriteLine("Parsed");
          }
          else
          {
             Console.WriteLine("Could not parse");
          }
      }
      

      【讨论】:

      • H 应该匹配 1 位或 2 位数字。您的代码构建了一个仅匹配一位数小时的正则表达式。
      • 谢谢,我已经更新了代码。认为现在这两种格式都应该适用。
      • @keyboardP 这就是我自己解析它的方式。您还需要考虑转义正则表达式字符,因为它们可用于日期时间格式的分隔符,您还需要处理日期时间格式转义.....
      • @KeithNicholas - 这只是一个想法的快速模拟。可能需要处理的案例很少,但我认为框架中没有内置的方法。
      • @keyboardP 是的......还有更多的情况,所以你最终会得到相当多的代码来将格式转换为正则表达式匹配。您可能无法处理特定案件。这就是为什么我想知道是否有更好的方法! :-)
      【解决方案5】:

      你可以试试这样的正则表达式:

      ^[0-9]+-[a-z A-z]+-[0-9]+\s[0-9]+:[0-9]+:[0-9]+
      

      【讨论】:

        【解决方案6】:

        除了 DateTime.TryParse(或 RegEx)之外,我不知道在 .NET 中执行此操作的任何其他内容。

        我会设置一个流标记器,只将候选标记对传递给 DateTime.TryParse(基于最小字符串长度的某种组合,一个可能的子字符串检查标记 0 上的一对破折号和标记 1 上的一对冒号等。确切的检查将取决于您支持多少日期/时间格式)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2017-01-26
          • 1970-01-01
          • 2023-03-08
          • 1970-01-01
          • 2013-06-18
          • 1970-01-01
          • 2019-11-13
          相关资源
          最近更新 更多