使用多个可选模式时订单的重要性

时间:2016-01-07 14:16:06

标签: java parsing java-8 java-time

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解析文本'星期四07-01-2016'

3 个答案:

答案 0 :(得分:3)

文档没有提到任何优先权,我认为你得到的结果是正常的。它是从左到右读取String格式的结果。

  • 让我们考虑第一种格式"[EEEE][E] dd-MM-yyyy"

    • "Thu 07-01-2016":API会尝试查找是否可以匹配第一个可选部分"[EEEE]"。引自DateTimeFormatter Javadoc关于文本标记

        

      正好4个模式字母将使用完整形式。

      在这种情况下,是一周中某一天的完整形式。这与"Thu"不匹配,因此将跳过可选部分。但是,第二个可选部分是"[E]",仍然引用

        

      少于4个模式字母将使用简短形式。

      所以这将匹配"Thu"。因此,可以正确理解要解析的字符串

    • "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:Text' Thursday 07-01-2016'无法解析在索引3

索引3对应"r"的{​​{1}},因此它意味着它能够解析,直到这一点。

答案 1 :(得分:2)

  

DateTimeFormatter中可选模式的顺序如何影响解析操作?

解析器尝试按照它在模式中出现的顺序匹配每个可选节。

请注意,字符串“Thursday”以“Thu”开头,可以与模式片段“E”匹配。接下来,观察在索引3处报告匹配失败,其对应于“星期四”中的'r'。错误情况下发生的情况是解析器将字符串的前三个字符与第一个可选部分匹配,跳过第二个可选部分,因为它与字符串的下一部分不匹配,然后无法匹配'r'。

换句话说,这些格式化程序不会回溯以尝试替代匹配。在正则表达式中,可选部分是贪婪的。

另请注意,您的两种模式都比您想要的更宽松。例如,您的模式p1将匹配字符串"ThursdayThu 07-01-2016"

答案 2 :(得分:1)

可选格式的顺序很重要:

当格​​式[E][EEEE] dd-MM-yyyy的解析器解析"Thursday 07-01-2016"时,

  • 使用可选部分Thu
  • 消费[E]
  • 跳过[EEEE],因为它无法识别漫长的一周
  • 现在需要一个空格并因为它看到r而失败,因此会抛出错误索引为3的异常。

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