DateTimeFormatter
中可选模式的顺序如何影响解析操作?
我在运行这个程序,想知道为什么最后一行抛出异常,而不是前三行。
public static void main(String[] args) {
String p1 = "[EEEE][E] dd-MM-yyyy";
String p2 = "[E][EEEE] dd-MM-yyyy";
String date1 = "Thu 07-01-2016";
String date2 = "Thursday 07-01-2016";
parse(date1, p1); //OK
parse(date1, p2); //OK
parse(date2, p1); //OK
parse(date2, p2); //Exception
}
private static void parse(String date, String pattern) {
DateTimeFormatter fmt = DateTimeFormatter.ofPattern(pattern, Locale.ENGLISH);
System.out.println(fmt.parse(date));
}
最后一行的异常是:
java.time.format.DateTimeParseException:无法在索引3 处解析文本"2016年1月7日星期四"
文档中没有提到任何优先级,我认为您得到的结果是正常的。它是从左到右读取字符串格式的结果。
-
让我们考虑第一种格式
"[EEEE][E] dd-MM-yyyy"
。-
"Thu 07-01-2016"
:API试图查找第一个可选部分"[EEEE]"
是否可以匹配。引用DateTimeFormatter
Javadoc关于文本标记正好4个图案字母将使用完整的表格。
在这种情况下,它是一周中某一天的完整形式。这与
"Thu"
不匹配,因此将跳过可选部分。然而,第二个可选部分是"[E]"
,并且仍然引用少于4个图案字母将使用缩写形式。
因此这将匹配CCD_ 8。因此,要解析的字符串可以正确理解
"Thursday 07-01-2016"
:与上面相同,只是它将在第一个可选部分与"Thursday"
匹配。但API仍将继续搜索下一个可选"[E]"
的有效部分,但找不到任何部分,因此跳过可选部分
-
- 现在让我们考虑第二种格式
"[E][EEEE] dd-MM-yyyy"
。"Thu 07-01-2016"
:API试图查找第一个可选部分"[E]"
是否可以匹配,并且它对"Thu"
有效。如上所述,API现在将尝试查找"[EEEE]"
的匹配项,但找不到任何匹配项,因此跳过可选部分"Thursday 07-01-2016"
:API试图再次匹配"[E]"
,这就是事情发生的地方:它确实匹配。"Thursday"
从"Thu"
开始,因此格式化程序能够找到匹配项。但随后,它尝试解析其余部分,即"rsday 07-01-2016"
。[EEEE]
可选部分将不匹配,因此将跳过它。然后它会因为空间而失败,因为剩下的空间已经没有了(取而代之的是"r"
)
所以如果你用运行你的代码
parse("ThuThursday 07-01-2016", "[E][EEEE] dd-MM-yyyy");
你会看到它是有效的:"[E]"
匹配"Thu"
,"[EEEE]"
匹配"Thursday"
。
请注意,异常消息也暗示了这一点(强调矿):
java.time.format.DateTimeParseException:无法在索引3处解析文本"2016年1月7日星期四"
索引3对应于"rsday"
的"r"
,所以这意味着它能够解析,直到现在。
DateTimeFormatter中可选模式的顺序如何影响解析操作?
解析器试图按照每个可选部分在模式中出现的顺序来匹配它。
请注意,字符串"Thursday"以"Thu"开头,可以通过模式片段"E"进行匹配。接下来,观察匹配失败在索引3中报告,该索引对应于"星期四"中的"r"。在错误情况下,解析器将字符串的前三个字符与第一个可选部分匹配,跳过第二个可选部分,因为它与字符串的下一部分不匹配,然后无法匹配"r"。
换句话说,这些格式化程序不会回溯以尝试替代匹配。在regex术语中,可选部分是贪婪的。
还要注意,您的两种模式可能都比您想要的更宽松。例如,您的模式p1
将与字符串"ThursdayThu 07-01-2016"
匹配。
可选格式的顺序很重要:
当格式[E][EEEE] dd-MM-yyyy
的解析器解析"Thursday 07-01-2016"
时,它是
- 使用可选部分
[E]
消耗Thu
- 跳过
[EEEE]
,因为它无法识别一周中的长一天 - 现在期望一个空间,但由于它看到
r
而失败,并因此抛出错误索引为3的异常
因此,如果您使用可选部分来允许解析替代版本(这里使用长或短的一周),请首先添加更具体的格式。