【问题标题】:Using RegEx to match Month-Day in C#在 C# 中使用 RegEx 匹配月-日
【发布时间】:2013-12-31 17:54:42
【问题描述】:

让我先说我是 Regex 和 C# 的新手,所以我仍在努力解决这个问题。我也意识到正则表达式是一个需要时间来理解的深层次的主题。我做了一些研究来弄清楚这一点,但我没有时间正确研究正则表达式语法的艺术,因为我需要明天完成这个程序。 (不,这不是作业,这是为了我的工作)

我正在使用 c# 逐行搜索文本文件,并尝试使用 Regex 表达式检查是否有任何行包含格式为 MM-DD 的当前月份的任何日期。 Regex 表达式在传递文件每一行的方法中使用。

这是我目前使用的方法:

private bool CheckTransactionDates(string line)
{ 
   // in the actual code this is dynamically set based on other variables
   string month = "12";

   Regex regExPattern = new Regex(@"\s" + month + @"-\d(0[1-9]|[1-2][0-9]|3[0-1])\s");
   Match match = regExPattern.Match(line);

   return match.Success;
}

如果它前面有一个空格,后面有一个空格,基本上我需要它来匹配。仅当它是当前月份(在本例中为 12)、连字符和月份中的某一天(“ 12-01 ”应匹配但不匹配“ 12-99 ”)时。连字符两侧应始终为 2 位数字。

这个正则表达式(我唯一能匹配的东西)会起作用,但也会挑选必要范围之外的项目:

Regex regExPattern = new Regex(@"\s" + month + @"-\d{2}\s");

我也试过这个没有成功:

Regex regExPattern = new Regex(@"\s" + month + @"-\d[01-30]{2}\s");

谁能告诉我我需要改变什么才能得到我需要的结果? 提前致谢。

【问题讨论】:

  • 您说像\s12-\d{2}\s 这样的模式匹配您不想要的其他项目,请提供它匹配的文本示例。显然,我们在这里是盲目的,因为我们不知道 Regex 失败的示例文件可能是什么样子。
  • 我不明白为什么只匹配有效的日期范围如此重要。如果您真的担心可能存在无效值,您可以在第二步中对其进行验证。有效日期取决于月份,因此仅使用正则表达式进行此验证很困难。
  • 看看这里:Regular Expression to match valid datesLMGTFY。让正则表达式专门匹配可能既困难又丑陋,但您可以使用正则表达式缩小范围并检查范围。
  • @Michael Perrenoud 它匹配的行的一个示例是:“ 11-20 2690 E 28.76 12-02 2468 E* 387.85” 但是它也会匹配这一行(我不希望它匹配匹配):“ 11-15 3610 E 29.34 12-87 2534 E* 465.85”
  • 你不能用DateTime.TryParseExtact吗?

标签: c# regex date search


【解决方案1】:

如果您只需要确定该行是否包含任何有效匹配项,则可以使用以下方法:

private bool CheckTransactionDates(string line)
{ 
   // in the actual code this is dynamically set based on other variables
   int month = DateTime.Now.Month;
   int daysInMonth = DateTime.DaysInMonth(DateTime.Today.Year, DateTime.Today.Month);

   Regex pattern = new Regex(string.Format(@"{0:00}-(?<DAY>[0123][0-9])", month));
   int day = 0;

   foreach (Match match in pattern.Matches(line))
   {
      if (int.TryParse(match.Groups["DAY"].Value, out day))
      {
         if (day <= daysInMonth)
         {
            return true;
         }
      }
   }

   return false;
}

它是这样工作的:

您确定要搜索的月份(这里,我使用当前月份),以及该月的天数。

接下来,正则表达式模式是使用 string.Format 函数构建的,该函数将左填充的月份加上破折号,然后是 从 00 到 39 的任意两位数字(@987654322 @ 表示第一个数字,[0-9] 表示第二个数字)。这缩小了正则表达式匹配的范围,但对于日期来说不是最终的。围绕它的(?&lt;DAY&gt;...) 创建了一个正则表达式组,这将使以后的处理更容易。请注意,我没有检查空格,以防该行以有效日期开头。您可以轻松地在模式中添加空格,或根据您的特定需求修改模式。

接下来,我们在循环中检查该行 (pattern.Matches) 上所有可能的匹配项。

如果找到匹配项,我们会尝试将其解析为整数(根据我们匹配的模式,它应该始终有效)。我们使用我们在模式中定义的匹配的DAY 组。

在将该匹配解析为整数day 后,我们检查该日期是否是指定月份的有效数字。如果是,我们从函数中返回 true,因为我们找到了一个有效的日期。

最后,如果我们没有找到匹配项,或者没有一个匹配项是有效的,我们会从函数中返回 false(仅当我们之前没有返回 true 时)。

【讨论】:

  • 这当然看起来可以满足我的需求......但是,我有点困惑。根据我在您和 Michael Perrenoud 的帖子中看到的内容,为什么在 01 和 31 之间无法获得 2 位数字: \d(0[1-9]|[1-2][0-9]|3 [0-1])
  • @pscapng - 您案例开头的 \d 匹配一个数字,然后您匹配其他条件。删除它,您将获得您正在尝试的“01-09 或 10-29 或 30-31”日案例。但是,这将为您在 2 月 31 日等提供匹配。关键是,仅使用正则表达式来确保有效的日期数据非常困难。
  • @WonkotheSane 谢谢你的解释......我现在明白了。由于每个人都说需要额外的编码来进一步验证输入,我认为投资回报率太低了。我最终只使用了 @"\s" + month + @"-\d{2}\s" 并且没有进一步验证。再次感谢大家的帮助
  • 没问题。但是,投资回报率只是复制此处给出的解决方案之一 - 免费验证。
【解决方案2】:

需要注意的是\s 匹配任何个空格字符,而不仅仅是一个空格:

\s 匹配任何空白字符 [\r\n\t\f ]

但是,字面上查找空格的正则表达式不会,例如(12-\d{2})。但是,我必须与社区的其他人一起讨论如何处理比赛。您将需要通过每场比赛并以更好的方法验证日期:

var input = string.Format(
    " 11-20 2690 E 28.76 12-02 2468 E* 387.85{0}11-15 3610 E 29.34 12-87 2534 E",
    Environment.NewLine);

var pattern = string.Format(@" ({0}-\d{{2}}) ", DateTime.Now.ToString("MM"));
var lines = new List<string>();

foreach (var line in input.Split(new string[] { Environment.NewLine },
    StringSplitOptions.RemoveEmptyEntries))
{
    var m = Regex.Match(line, pattern);
    if (!m.Success)
    {
        continue;
    }

    DateTime dt;
    if (!DateTime.TryParseExact(m.Value.Trim(),
        "MM-dd",
        null,
        DateTimeStyles.None,
        out dt))
    {
        continue;
    }
    lines.Add(line);
}

我一次通过一行的原因是因为大概你需要知道哪一行是好的,哪一行是坏的。我的逻辑可能不完全符合你的需要,但你可以轻松修改。

【讨论】:

    猜你喜欢
    • 2011-11-10
    • 1970-01-01
    • 1970-01-01
    • 2018-08-12
    • 1970-01-01
    • 2012-09-26
    • 2021-06-09
    • 2020-09-01
    • 2015-12-10
    相关资源
    最近更新 更多