这很奇怪,因为它是 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
)并简单地交换 sDay
和sMonth
在已编译的正则表达式中,您实际上会注意到 month
将正确匹配两个数字,而 day
将失败!
解决此问题的一种方法是首先匹配双字符规则,然后匹配可选的单字符规则,就像我的回答所建议的那样。另一种方法是假设/要求您的输入日期单独在一行上(即日期从行首开始到行尾结束,没有其他文本)。如果是这样,则可以使用正则表达式的 ^
和 $
字符分别匹配行的开头和结尾:
Pattern.compile("^(" + sDay + ")" + "(?:" + sSeparators + ")" + "(" + sMonth+ ")$");
这样做,它将完全评估每个模式以找到完整的匹配项,在这种情况下,您应该始终匹配正确的月份/日期。
站点注释(建议,但不是特定答案)
根据@MarkoTopolnik 的有用评论/建议,您不需要在每个组(月 + 天)周围使用非捕获组,特别是因为您立即将它们包装在捕获组中,使非捕获组无用。所以,上面的模式可以简单地变成:
1[0-2]|0?[1-9]
关于java - 日期的正则表达式省略月份部分的一个字符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13068823/