c# - 以各种格式呈现时解析日期的推荐方法

标签 c# datetime date-parsing

我有一个日期集合,作为用户在一段时间内输入的字符串。由于这些来自人类,几乎没有或没有经过验证,因此为日期输入的格式差异很大。以下是一些示例(前导数字仅供引用):

  1. 1897 年 8 月 20 日、21 日
  2. 1909 年 5 月 31 日,6 月 1 日
  3. 2007 年 1 月 29 日
  4. 1954 年 5 月 10 日、11 日、12 日
  5. 2006 年 3 月 26、27、28、29、30
  6. 2006年11月27日、28日、29日、30日、12月1日

我想在 C# 中解析这些日期,以得到一组 DateTime 对象,每天一个 DateTime 对象。因此,上面的 (1) 会产生 2 个 DateTime 对象,而 (6) 会产生 5 个 DateTime 对象。

最佳答案

我会建议对它们进行泛化处理(基本上删除数字和名称并使它们成为占位符),然后按类似格式分组,这样您就有了一个样本组可以使用。

例如,20th, 21st August 1987然后变成[number][postfix], [number][postfix] [month] [year] (假设 <number><st|th|rd|nd> 被识别为数字,后缀和月份很明显,年份是 4 位数字)。

从那里,您可以了解有多少人遵循该模式,然后找到您需要匹配的独特模式有多少。然后你至少可以有一个样本来测试你想使用的任何类型的算法(正则表达式可能是你最好的选择,因为它可以检测重复的模式(#th[, $th[, ...]])和日期名称。)


看来您可能想按模式将其分解(根据您提供的内容)。因此,例如首先列出年度信息:

(.*?)([0-9]{4})(?:, |$)

然后你需要把它分解成几个月

(.*?)(January|February|...)(?:, |$)

那么你想要那个月中包含的天数:

(?:([0-9]{1,2})(?:st|nd|rd|th)(?:, )?)*(?:, |$)

接下来就是整理资料了。但同样,这只是使用你在我面前的东西。最终,您需要了解您正在处理的数据类型以及您希望如何处理这些数据。


已更新

所以,我忍不住尝试自己解决这个问题。我想证明我使用的方法有些准确,而且我没有在你的裙子上吹烟。话虽如此,这就是我想出的。请注意,这是在 PHP 中的几个原因:

  1. PHP 更容易上手
  2. 我觉得如果这一个可行的解决方案,您应该努力将其移植过来。 :咧嘴笑:

无论如何,这是源代码和演示输出。享受吧。

<?php
  $samples = array(
    '20th, 21st August 1897',
    '31st May, 1st June 1909',
    '29th January 2007',
    '10th, 11th, 12th May 1954',
    '26th, 27th, 28th, 29th, 30th March 2006',
    '27th, 28th, 29th, 30th November, 1st December 2006',
    '30th, 31st, December 2010, 1st, 2nd January 2011'
  );

  //header('Content-Type: text/plain');

  $months = array('january','february','march','april','may','june','july','august','september','october','november','december');

  foreach ($samples as $sample)
  {
    $dates = array();

    // find yearly information first
    $yearly = null;
    if (preg_match_all('/(?:^|\s)(?<month>.*?)\s?(?<year>[0-9]{4})(?:$|,)/',$sample,$yearly))
    {//var_dump($yearly);
      for ($y = 0; $y < count($yearly[0]); $y++)
      {
        $year = $yearly['year'][$y];
        //echo "year: {$year}\r\n";

        $monthly = null;
        if (preg_match_all('/(?<days>(?:(?:^|\s)[0-9]{1,2}(?:st|nd|rd|th),?)*)\s?(?<month>'.implode('|',$months).')$/i',$yearly['month'][$y],$monthly))
        {//var_dump($monthly);
          for ($m = 0; $m < count($monthly[0]); $m++)
          {
            $month = $monthly['month'][$m];
            //echo "month: {$month}\r\n";

            $daily = null;
            if (preg_match_all('/(?:^|\s)(?<day>[0-9]{1,2})(?:st|nd|rd|th)(?:,|$)/i',$monthly['days'][$m],$daily))
            {//var_dump($daily);
              for ($d = 0; $d < count($daily[0]); $d++)
              {
                $day = $daily['day'][$d];
                //echo "day: {$day}\r\n";

                $dates[] = sprintf("%d-%d-%d", array_search(strtolower($month),$months)+1, $day, $year);
              }
            }
          }
        }
        $data = $yearly[1];
      }
    }

    echo "<p><b>{$sample}</b> was parsed to include:</p><ul>\r\n";
    foreach ($dates as $date)
      echo "<li>{$date}</li>\r\n";
    echo "</ul>\r\n";
  }
?>

1897 年 8 月 20 日、21 日被解析为包括:

  • 8-20-1897
  • 8-21-1897

1909 年 5 月 31 日,6 月 1 日被解析为包括:

  • 6-1-1909

2007 年 1 月 29 日被解析为包括:

  • 2007 年 1 月 29 日

1954 年 5 月 10 日、11 日、12 日被解析为包括:

  • 5-10-1954
  • 5-11-1954
  • 5-12-1954

2006 年 3 月 26 日、27 日、28 日、29 日、30 日被解析为包括:

  • 2006 年 3 月 26 日
  • 2006 年 3 月 27 日
  • 2006 年 3 月 28 日
  • 2006 年 3 月 29 日
  • 2006 年 3 月 30 日

2006 年 11 月 27 日、28 日、29 日、30 日、12 月 1 日被解析为包括:

  • 12-1-2006

2010 年 12 月 30 日、31 日、2011 年 1 月 1 日、2 日被解析为包括:

  • 2010 年 12 月 30 日
  • 2010 年 12 月 31 日
  • 2011 年 1 月 1 日
  • 2011 年 1 月 2 日

为了证明我没有袖手旁观,http://www.ideone.com/GGMaH

关于c# - 以各种格式呈现时解析日期的推荐方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5023904/

相关文章:

c# - 在 C# 中键入时查找

c# - 从工作线程更新 UI 控件时出现死锁

c# - 在 ASP.NET MVC 和 C# 中将 System.Exception 转换为友好的 HTML

groovy - 使用 stanford nlp 查找日期及其在字符串中的位置

javascript - 在 JavaScript 中将字符串解析为日期

c# - 初学者 ILNumerics : install under VS2012

MySQL:UTC 到本地时区的自动映射

mysql - PHP : Parse all data from mysql where the 3rd and 4th digit of the id

sql - 设置 SQL Server 存储过程的默认参数

java - 如何将不同的日期字符串解析为LocalDate/Year?