使用多个可选模式时顺序的重要性



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的异常

因此,如果您使用可选部分来允许解析替代版本(这里使用长或短的一周),请首先添加更具体的格式。

最新更新