java - 日期的正则表达式省略月份部分的一个字符

标签 java regex date regex-group

这很奇怪,因为它是 dd/mm 格式的非常简单的正则表达式。结果应该是:"Group 1: 14; Group 2: 12" 但它是 "Group 1: 14; Group 2: 1"

第二组只捕获了第一个字符,但忽略了第二个字符(示例中的'2')。

String sDay = "(?:0?[1-9]|[12][0-9]|3[01])";
String sMonth = "(?:0?[1-9]|1[0-2])";
String sDot = "[\\.]";
String sSlash = "[/]";
String sMinus = "[\\-]";
String sSeparators = (sDot + "|" + sSlash + "|" + sMinus);

Pattern reDayMonth =
    Pattern.compile("(" + sDay + ")" + "(?:" + sSeparators + ")" + "(" + sMonth+ ")");

String s = "14/12";
Matcher reMatcher = reDayMonth.matcher(s);
boolean found = reMatcher.find();

System.out.println("Group 1: " + reMatcher.group(1) + "; Group 2: " + reMatcher.group(2));

我不明白为什么。你能帮帮我吗?

最佳答案

在您的月份正则表达式中,您允许首先匹配一个数字,它确实如此(然后停止)。尝试先移动所需的两位数月份以检查,然后然后检查个位数:

(?:0?[1-9]|1[0-2])

应该变成:

(?:1[0-2]|0?[1-9])

更新(推理)
0? 开头的相同模式在 day 模式中起作用但在 month 模式中不起作用的原因是因为您指定有些字符必须遵循 day 模式 - 因此,将处理 day 的整个模式。但是,在 month 模式中,没有指定后面的字符;因此,它会在找到第一个匹配项时停止,该匹配项在原始模式中是单个数字。

如果您要反转输入格式(即您使用 mm/dd 而不是 dd/mm)并简单地交换 sDaysMonth 在已编译的正则表达式中,您实际上会注意到 month 将正确匹配两个数字,而 day 将失败!

解决此问题的一种方法是首先匹配双字符规则,然后匹配可选的单字符规则,就像我的回答所建议的那样。另一种方法是假设/要求您的输入日期单独在一行上(即日期从行首开始到行尾结束,没有其他文本)。如果是这样,则可以使用正则表达式的 ^$ 字符分别匹配行的开头和结尾:

Pattern.compile("^(" + sDay + ")" + "(?:" + sSeparators + ")" + "(" + sMonth+ ")$");

这样做,它将完全评估每个模式以找到完整的匹配项,在这种情况下,您应该始终匹配正确的月份/日期。

站点注释(建议,但不是特定答案)
根据@MarkoTopolnik 的有用评论/建议,您不需要在每个组(月 + 天)周围使用非捕获组,特别是因为您立即将它们包装在捕获组中,使非捕获组无用。所以,上面的模式可以简单地变成:

1[0-2]|0?[1-9]

关于java - 日期的正则表达式省略月份部分的一个字符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13068823/

相关文章:

java - Neo4j 的 php api 与 java 遍历框架

Android 从 sqlite db 获取包含今天或之前日期的项目

php - 使用 PHP 和 MySQL 检查重叠日期

javascript正则表达式段落不以句号结尾

javascript - js正则表达式提取字母之间的空格。积极回顾?

java - 如何将自动时间戳表条目从纪元时间更改为现在?

java - jsp和servlet之间通讯错误?

Java 属性驱动集合

java - 为什么这是一个无法访问的语句?

PHP 正则表达式缺少两个匹配项