捕获下一行的正则表达式 Date/Time YYYY/MM/DD HH:mm 或 YYYY/M/D H:m

Regex to Capture next line Date/Time YYYY/MM/DD HH:mm or YYYY/M/D H:m

我想捕捉日期格式 - yyyy/mm/dd hh:mm

[^\n\r]*[\r\n]+([12]\d{3}/(0[1-9]|1[0-2])/(0[1-9]|[12]\d|3[0‌​1]))** 

上面的表达式捕获下一行到当天,但我也想包括时间部分,并且还想捕获月份、日期和时间的个位数,而不是必须输入两位数。

例如。用户可以输入 2017/5/2 9:52017/05/02 09:05

需要有关捕获个位数月和日以及时间部分的帮助。

要使数字可选,只需使用 the ? quantifier

假设您使用 classes PatternMatcher 来自 java.util.regex 包,您的代码将是这样的(另请注意在 Java 中你必须转义反斜杠 ,因此模式 \d 必须写成 \d):

String input = "2017/5/2 9:5";

Pattern pattern = Pattern.compile("(\d{4})/(0?[1-9]|1[0-2])/(0?[1-9]|[12]\d|3[0‌​1]) ([01]?\d|2[0-3]):([0-5]?\d)");

Matcher matcher = pattern.matcher(input);
while (matcher.find()) {
    String year = matcher.group(1);
    String month = matcher.group(2);
    String day = matcher.group(3);
    String hour = matcher.group(4);
    String minute = matcher.group(5);
}

对于月份和日期,我只是在零之后添加了一个 ?,使其成为可选的。

这个小时,我做了:

  • [01]?:可选零或一,后接任意数字(\d),
  • 2[0-3]:数字 2,后跟 0、1、2 或 3(因此小时数从 20 到 23)

会议纪要:

  • [0-5]?: 0到5的可选数字
  • 后跟任意数字 (\d)

这也适用于输入为零的情况,例如 "2017/05/02 09:05"。您可以选择将 String 值转换为 int,使用 Integer.parseInt(matcher.group(1)).


为什么不使用 date/time API?

上面的代码不会检查所有有效日期的情况,例如一个月中的天数(包括闰年的二月)。尽管可以使用正则表达式来完成,但它会非常复杂且难以维护,IMO 最好为此使用适当的 API(只是闰年验证是 a very complex expression by itself) .

如果您编写此代码只是为了学习目的,那很好。但是对于实际的业务应用程序,最好使用 date/time API(regex 很棒,但并不总是最好的工具)。

如果您正在使用 Java 8,请考虑使用 new java.time API. It's easier, less bugged and less error-prone than the old APIs.

如果您使用 Java 6 或 7,您可以使用 ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, you'll also need the ThreeTenABP (more on how to use it here).

下面的代码适用于两者。 唯一的区别是包名称(在 Java 8 中是 java.time,在 ThreeTen Backport(或 Android 的 ThreeTenABP)中是 org.threeten.bp),但是 classes和方法名称相同。

首先,您可以使用 DateTimeFormatter and parse the input to a LocalDateTime(代表日期和时间的 class,与您的输入数据完美匹配)。然后你使用这个 class 来获取你想要的字段:

String input = "2017/5/2 9:5";

// pattern with optional zero for month, day, hour and minute
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy/M/d H:m")
    // use strict mode to validate dates like Feb 29th
    .withResolverStyle(ResolverStyle.STRICT);
LocalDateTime dt = LocalDateTime.parse(input, fmt);
int year = dt.getYear();
int month = dt.getMonthValue();
int day = dt.getDayOfMonth();
int hour = dt.getHour();
int minute = dt.getMinute();

这也适用于 "2017/05/02 09:05"。这也有检查无效值的优点(如月份 > 12,或闰年的 Feb 29th 等)。

如果不使用严格模式,non-leap年2月29日调整为2月28日 (这是 smart resolver style, which is the default 的行为)。

Check the javadoc 对于 DateTimeFormatter 接受的所有可用模式。

这里是...

  \d{4}\/([1-9]{1}|0[1-9]|1[0-2])\/([1-9]{1}|[0-2]{1}[1-9]{1}|3[0-1])\s+([0-9]{1}|[0-1]{1}[0-9]{1}|2[0-4]):([0-9]{1}|[0-5]{1}[0-9]{1})\s+

这似乎让人不知所措,所以这里是表达式的演练。 此表达式不仅会查找日期和时间,还会忽略不切实际的日期时间,例如 2001/44/442344/44444/999。它仅检查有效的日期时间。无效的日期时间将是 ignored.Also 它不仅会检查行首的日期时间,还会检查字符串中的任何位置,无论字符串是单行还是多行。

说明

第 4 位数字将是年份....

\d{4}

后跟'/'...

\d{4}\/

现在,月份可以是个位数,例如 1-9

\d{4}\/( [1-9]{1} )

或两位数01、02、03、09(这里记住如果月份以0开头,那么它的第二位数字不能大于9。)

\d{4}\/( [1-9]{1} | 0[1-9]{1} )

或 10、11、12 但不能大于 12。

\d{4}\/( [1-9]{1} | 0[1-9]{1} | 1[0-2]{1} )

后跟一个“/”

\d{4}\/( [1-9]{1} | 0[1-9]{1} | 1[0-2]{1} ) \/

现在有天了,可以是个位数1-9

\d{4}\/( [1-9]{1} | 0[1-9]{1} | 1[0-2]{1} ) \/( [1-9]{1} )

或两位数 01、02、03、09、19、29。

\d{4}\/( [1-9]{1} | 0[1-9]{1} | 1[0-2]{1} ) \/( [1-9]{1} | [0-2]{1}[1-9]{1} )

或者它可以是 30 或 31,但不能大于它。

\d{4}\/( [1-9]{1} | 0[1-9]{1} | 1[0-2]{1} ) \/( [1-9]{1} | [0-2]{1}[1-9]{1} | 3[0-1] )

现在日期部分已经完成。日期和时间之间有些 space。

\d{4}\/( [1-9]{1} | 0[1-9]{1} | 1[0-2]{1} ) \/( [1-9]{1} | [0-2]{1}[1-9]{1} | 3[0-1] ) \s+

现在让我们关注时间部分。 假设时间基于 24 小时格式。 小时可以是单个数字,如 0、1、2、9

( [0-9]{1} )

或两位数,如 01、02、09、11、19

( [0-9]{1} | [0-1]{1}[0-9]{1} )

或 20、21、22、23、24 但不大于 24。

( [0-9]{1} | [0-1]{1}[0-9]{1} | 2[0-4]{1} )

后跟“:”

( [0-9]{1} | [0-1]{1}[0-9]{1} | 2[0-4]{1} ) : 

分钟可以是个位数,例如 0、1、2、9...

( [0-9]{1} | [0-1]{1}[0-9]{1} | 2[0-4]{1} ) : ( [0-9]{1} )

或两位数,如 01、02、03、23、44、59(不是 60)。

( [0-9]{1} | [0-1]{1}[0-9]{1} | 2[0-4]{1} ) : ( [0-9]{1} | [0-5]{1}[0-9]{1} )

其次是一些 space

( [0-9]{1} | [0-1]{1}[0-9]{1} | 2[0-4]{1} ) : ( [0-9]{1} | [0-5]{1}[0-9]{1} )
\s+

现在结合您的日期正则表达式和时间正则表达式,您将得到

\d{4}\/([1-9]{1}|0[1-9]|1[0-2])\/([1-9]{1}|[0-2]{1}[1-9]{1}|3[0-1])\s+([0-9]{1}|[0-1]{1}[0-9]{1}|2[0-4]):([0-9]{1}|[0-5]{1}[0-9]{1})\s+

注意:在解释过程中,为了更好的可读性,我在正则表达式中添加了额外的space。