人类可读时间的正则表达式 - 下午5点,下午5点30分,中午12点

时间:2016-09-29 00:30:33

标签: c# regex parsing momentjs

我试图解析的一些事情是:

8am, 12.10pm, 5.45pm 
8am, 11.30am
12noon
12 noon
8 am
7 pm. 

我有以下内容而不适合中午 - 但它并没有捕获上述所有情况。

^([0-9]|0[0-9]|1[0-9]|2[0-3]).[0-5][0-9][a|p]m$

4 个答案:

答案 0 :(得分:1)

验证应该在正则表达式之外进行,因为它不是基于语义,而是基于我们对时间的理解。 虽然我们可以在正则表达式中做到这一点,但它会使模式非常混乱。

模式的基本形式应该是这样,简单直接:

\d{1,2}(\.\d{1,2})? ?([a|p]m|noon)

但是,我们必须添加一些命名组来隔离不同时间段:

  1. 小时:(?<hours>\d{1,2})
  2. 分钟:(?<minutes>\d{1,2})
  3. 期间:(?<period>[ap]m|noon)
  4. 合并所有togather:@"(?<hours>\d{1,2})(\.(?<minutes>\d{1,2}))? ?(?<period>[ap]m|noon)"

    以下代码捕获看起来像人类可读时间的字符串的所有部分,只是在您的示例中找到的那些部分,并将其解析为TimeSpan对象:

    var times = Regex.Matches(input, @"(?<hours>\d{1,2})(\.(?<minutes>\d{1,2}))? ?(?<period>[ap]m|noon)")
        .Cast<Match>()
        // parse parts of time
        .Select(m => new
        {
            Hours = int.Parse(m.Groups["hours"].Value),
            Minutes = m.Groups["minutes"].Success ? int.Parse(m.Groups["minutes"].Value) : 0,
            IsAfternoon = Regex.IsMatch(m.Groups["period"].Value, "pm|noon"),
        })
        // filter out invalid time
        .Where(x => x.Hours <= 12 && x.Minutes <= 59)
        // convert
        .Select(x => new TimeSpan((x.Hours + (x.IsAfternoon ? 12 : 0)) % 24, x.Minutes, 0));
    
    编辑:我们有一种奇怪的方式来记下时间:下午1点= 13点,下午2点= 14点,... 11点= 23点,下午12点!= 24点(但= = 12点)。而且,上面的例子没有考虑到这一点。

    所以这里有一个修复:

    var input = @" Monday 8am, 12.10pm, 5.45pm, 14:24||8:0|0:10|17:45";
    var results = Regex.Matches(input, @"(?<hours>\d{1,2})([\.:](?<minutes>\d{2}))?(?<period>[ap]m|noon)?")
        .Cast<Match>()
        .Where(m => m.Groups["minutes"].Success || m.Groups["period"].Success)
        .Select(m => new
        {
            Hours = int.Parse(m.Groups["hours"].Value),
            Minutes = m.Groups["minutes"].Success ? int.Parse(m.Groups["minutes"].Value) : 0,
            IsAfternoon = m.Groups["period"].Success ? Regex.IsMatch(m.Groups["period"].Value, "pm|noon") : (bool?)null
        })
        .Dump()
        .Where(x => (x.IsAfternoon != null ? x.Hours <= 12 : x.Hours < 24) && x.Minutes <= 59)
        .Select(x => new TimeSpan(
            x.Hours == 12 && x.IsAfternoon == true
                ? 12 
                : x.Hours + (x.IsAfternoon == true ? 12 : 0),
            x.Minutes,
            0));
    

    结果:

      

    8点00分00秒
      12时10分00秒
      17:45:00
      14时24分00秒
      00:10:00
      17:45:00

答案 1 :(得分:1)

如果您想使用原始问题中所述的时刻,您可以:

  • 自定义您的语言区域以解析&#39;中午&#39;喜欢下午
  • 使用多种格式解析时刻

您可以moment.updateLocale使用meridiemParse指定isPM['ha', 'h a', 'h.mma']

然后,您可以使用docs指定所需的每种格式(示例中为moment.updateLocale('en', { meridiemParse : /[ap]\.?m?\.?|noon/i, isPM : function (input) { input = (input + '').toLowerCase(); return input[0] === 'p' || input === 'noon'; } }); var arr = ['8am', '12.10pm', '5.45pm', '11.30am', '12noon', '12 noon', '8 am', '7 pm.']; for(var i=0; i<arr.length; i++){ var m = moment(arr[i], ['ha', 'h a', 'h.mma'], true); console.log(m.format('HH:mm'), arr[i]); })。

这是问题中给出的输入的一个工作示例:

&#13;
&#13;
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.15.1/moment.min.js"></script>
&#13;
{{1}}
&#13;
&#13;
&#13;

答案 2 :(得分:1)

我希望这一切都能完成:)这是对你自己尝试的一点修改。

(?<![\d.])                              # Mustn't be preceeded by a digit or .
    (?:
        12\s*noon                       # just 12 noon
    |    
        (?:[0-9]|0[0-9]|1[0-2])         # 12 hour clock
        (?:\.[0-5][0-9])?               # optional minutes
        \s*(?:[ap]m)                    # mandatory am/pm
    |
        (?:[0-9]|0[0-9]|1[0-9]|2[0-3])  # 24 hour clock
        (?:\.[0-5][0-9])?               # optional minutes
    )
(?![\d.]|[ap]m)                         # Correct ending

Check it out here at regex101

PS。您已将其标记为c#,因此我认为后台是可以的。 (还有momentjs标签让我不确定。)

答案 3 :(得分:0)

(1[0-2]|[0-9])(\.[0-5]?[0-9])?\s?([a|p]m|noon)

证明:https://regex101.com/r/9yu6l6/2

编辑:根据边缘情况重新编写