【问题标题】:Importance of order when using multiple optional patterns使用多个可选模式时顺序的重要性
【发布时间】:2016-01-07 14:16:05
【问题描述】:

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 处解析文本 'Thursday 07-01-2016'

【问题讨论】:

  • 如果java.time 提供带有后备模式(如jodatime)的DateTimeFormatter,我会很好。
  • @SotiriosDelimanolis 有一个关于在解析中添加对“OR”的支持的增强请求:JDK-8132536
  • @Tunaki Java 的错误跟踪站点太慢了。希望请求被接受。

标签: java parsing java-8 java-time


【解决方案1】:

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

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

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

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

      在这种情况下是星期几的完整形式。这与 "Thu" 不匹配,因此将跳过可选部分。然而,第二个可选部分是"[E]",并且仍在引用

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

      所以这将匹配"Thu"。从而可以正确理解要解析的String

    • "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 对应于 "rsday""r",因此这意味着它能够解析,直到这一点。

【讨论】:

    【解决方案2】:

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

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

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

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

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

    【讨论】:

      【解决方案3】:

      可选格式的顺序很重要:

      [E][EEEE] dd-MM-yyyy格式的解析器解析"Thursday 07-01-2016"然后它

      • 使用可选部分[E] 使用Thu
      • 跳过 [EEEE],因为它无法识别较长的星期几
      • 现在需要一个空格并失败,因为它看到了r,因此引发了错误索引为 3 的异常。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-01-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-27
        • 2016-08-09
        相关资源
        最近更新 更多