如何在 Java DateTime API 中解析带有日文数字的日期字符串
How to Parse Date Strings with Japanese Numbers in Java DateTime API
问了[]后,
对下面的案例很好奇;
明治二十三年十一月二十九日
有没有办法将日本日历字符之上的 Japanese numbers(本质上是 纯 日本日期)解析为 LocalDate
?仅使用 Java 日期时间 API。我不想修改输入字符串值,但只想 API 来处理识别。
对于阅读的任何人,您的示例日期字符串包含一个纪元指示符、纪元年份 23(在本例中对应于 1890 CE Gregorian)、第 11 月和第 29 月的第几天。月份和日期与在公历中。
由于日语数字不完全是位置性的(例如阿拉伯数字),DateTimeFormatter
不会自行解析它们。因此,我们通过提供数字在日语(和中文)中的外观来帮助它。 DateTimeFormatterBuilder
有一个重载的 appendText
方法,它接受一个将所有可能的数字保存为文本的映射。我的代码示例不完整,但应该可以帮助您入门。
Locale japaneseJapan = Locale.forLanguageTag("ja-JP");
Map<Long, String> numbers = Map.ofEntries(
Map.entry(1L, "\u4e00"),
Map.entry(2L, "\u4e8c"),
Map.entry(3L, "\u4e09"),
Map.entry(4L, "\u56db"),
Map.entry(5L, "\u4e94"),
Map.entry(6L, "\u516d"),
Map.entry(7L, "\u4e03"),
Map.entry(8L, "\u516b"),
Map.entry(9L, "\u4e5d"),
Map.entry(10L, "\u5341"),
Map.entry(11L, "\u5341\u4e00"),
Map.entry(12L, "\u5341\u4e8c"),
Map.entry(13L, "\u5341\u4e09"),
Map.entry(14L, "\u5341\u56db"),
Map.entry(15L, "\u5341\u4e94"),
Map.entry(16L, "\u5341\u516d"),
Map.entry(17L, "\u5341\u4e03"),
Map.entry(18L, "\u5341\u516b"),
Map.entry(19L, "\u5341\u4e5d"),
Map.entry(20L, "\u4e8c\u5341"),
Map.entry(21L, "\u4e8c\u5341\u4e00"),
Map.entry(22L, "\u4e8c\u5341\u4e8c"),
Map.entry(23L, "\u4e8c\u5341\u4e09"),
Map.entry(24L, "\u4e8c\u5341\u56db"),
Map.entry(25L, "\u4e8c\u5341\u4e94"),
Map.entry(26L, "\u4e8c\u5341\u516d"),
Map.entry(27L, "\u4e8c\u5341\u4e03"),
Map.entry(28L, "\u4e8c\u5341\u516b"),
Map.entry(29L, "\u4e8c\u5341\u4e5d"),
Map.entry(30L, "\u4e09\u4e8c\u5341"));
DateTimeFormatter japaneseformatter = new DateTimeFormatterBuilder()
.appendPattern("GGGG")
.appendText(ChronoField.YEAR_OF_ERA, numbers)
.appendLiteral('\u5e74')
.appendText(ChronoField.MONTH_OF_YEAR, numbers)
.appendLiteral('\u6708')
.appendText(ChronoField.DAY_OF_MONTH, numbers)
.appendLiteral('\u65e5')
.toFormatter(japaneseJapan)
.withChronology(JapaneseChronology.INSTANCE);
String dateString = "明治二十三年十一月二十九日";
System.out.println(dateString + " is parsed into " + LocalDate.parse(dateString, japaneseformatter));
这个例子的输出是:
明治二十三年十一月二十九日 is parsed into 1890-11-29
假设一个时代可以超过 30 年,您需要向地图提供更多数字。你可以比我做得更好(并且还可以检查我的数字是否有错误)。使用几个嵌套循环来填充地图可能是最好的(更不容易出错),但我不确定我是否能正确完成,所以我把这部分留给你。
今天我学习了一些关于日本数字的知识。
我使用的一些链接
迟到的答案,但被接受的答案有点冗长而且不太容易完成,所以我认为我的建议是一个很好而有力的选择。
使用我的库 Time4J which supports Japanese numerals out of the box and then use the embedded Japanese calendar:
String input = "明治二十三年十一月二十九日";
ChronoFormatter<JapaneseCalendar> f =
ChronoFormatter.ofPattern(
"GGGGy年M月d日",
PatternType.CLDR,
Locale.JAPANESE,
JapaneseCalendar.axis()
).with(Attributes.NUMBER_SYSTEM, NumberSystem.JAPANESE);
JapaneseCalendar jcal = f.parse(input);
LocalDate gregorian = jcal.transform(PlainDate.axis()).toTemporalAccessor();
System.out.println(gregorian); // 1890-11-29
这个解决方案不仅更短而且甚至适用于明治 6 年之前的日本历史日期(基于古代的旧阴阳历)。此外,一个时代的第一年(实际上我们有这样的一年)的 gannen 表示法比标准 java 得到更好的支持(您必须使用自定义地图再次应用冗长的解决方法)。
问了[
对下面的案例很好奇;
明治二十三年十一月二十九日
有没有办法将日本日历字符之上的 Japanese numbers(本质上是 纯 日本日期)解析为 LocalDate
?仅使用 Java 日期时间 API。我不想修改输入字符串值,但只想 API 来处理识别。
对于阅读的任何人,您的示例日期字符串包含一个纪元指示符、纪元年份 23(在本例中对应于 1890 CE Gregorian)、第 11 月和第 29 月的第几天。月份和日期与在公历中。
由于日语数字不完全是位置性的(例如阿拉伯数字),DateTimeFormatter
不会自行解析它们。因此,我们通过提供数字在日语(和中文)中的外观来帮助它。 DateTimeFormatterBuilder
有一个重载的 appendText
方法,它接受一个将所有可能的数字保存为文本的映射。我的代码示例不完整,但应该可以帮助您入门。
Locale japaneseJapan = Locale.forLanguageTag("ja-JP");
Map<Long, String> numbers = Map.ofEntries(
Map.entry(1L, "\u4e00"),
Map.entry(2L, "\u4e8c"),
Map.entry(3L, "\u4e09"),
Map.entry(4L, "\u56db"),
Map.entry(5L, "\u4e94"),
Map.entry(6L, "\u516d"),
Map.entry(7L, "\u4e03"),
Map.entry(8L, "\u516b"),
Map.entry(9L, "\u4e5d"),
Map.entry(10L, "\u5341"),
Map.entry(11L, "\u5341\u4e00"),
Map.entry(12L, "\u5341\u4e8c"),
Map.entry(13L, "\u5341\u4e09"),
Map.entry(14L, "\u5341\u56db"),
Map.entry(15L, "\u5341\u4e94"),
Map.entry(16L, "\u5341\u516d"),
Map.entry(17L, "\u5341\u4e03"),
Map.entry(18L, "\u5341\u516b"),
Map.entry(19L, "\u5341\u4e5d"),
Map.entry(20L, "\u4e8c\u5341"),
Map.entry(21L, "\u4e8c\u5341\u4e00"),
Map.entry(22L, "\u4e8c\u5341\u4e8c"),
Map.entry(23L, "\u4e8c\u5341\u4e09"),
Map.entry(24L, "\u4e8c\u5341\u56db"),
Map.entry(25L, "\u4e8c\u5341\u4e94"),
Map.entry(26L, "\u4e8c\u5341\u516d"),
Map.entry(27L, "\u4e8c\u5341\u4e03"),
Map.entry(28L, "\u4e8c\u5341\u516b"),
Map.entry(29L, "\u4e8c\u5341\u4e5d"),
Map.entry(30L, "\u4e09\u4e8c\u5341"));
DateTimeFormatter japaneseformatter = new DateTimeFormatterBuilder()
.appendPattern("GGGG")
.appendText(ChronoField.YEAR_OF_ERA, numbers)
.appendLiteral('\u5e74')
.appendText(ChronoField.MONTH_OF_YEAR, numbers)
.appendLiteral('\u6708')
.appendText(ChronoField.DAY_OF_MONTH, numbers)
.appendLiteral('\u65e5')
.toFormatter(japaneseJapan)
.withChronology(JapaneseChronology.INSTANCE);
String dateString = "明治二十三年十一月二十九日";
System.out.println(dateString + " is parsed into " + LocalDate.parse(dateString, japaneseformatter));
这个例子的输出是:
明治二十三年十一月二十九日 is parsed into 1890-11-29
假设一个时代可以超过 30 年,您需要向地图提供更多数字。你可以比我做得更好(并且还可以检查我的数字是否有错误)。使用几个嵌套循环来填充地图可能是最好的(更不容易出错),但我不确定我是否能正确完成,所以我把这部分留给你。
今天我学习了一些关于日本数字的知识。
我使用的一些链接
迟到的答案,但被接受的答案有点冗长而且不太容易完成,所以我认为我的建议是一个很好而有力的选择。
使用我的库 Time4J which supports Japanese numerals out of the box and then use the embedded Japanese calendar:
String input = "明治二十三年十一月二十九日";
ChronoFormatter<JapaneseCalendar> f =
ChronoFormatter.ofPattern(
"GGGGy年M月d日",
PatternType.CLDR,
Locale.JAPANESE,
JapaneseCalendar.axis()
).with(Attributes.NUMBER_SYSTEM, NumberSystem.JAPANESE);
JapaneseCalendar jcal = f.parse(input);
LocalDate gregorian = jcal.transform(PlainDate.axis()).toTemporalAccessor();
System.out.println(gregorian); // 1890-11-29
这个解决方案不仅更短而且甚至适用于明治 6 年之前的日本历史日期(基于古代的旧阴阳历)。此外,一个时代的第一年(实际上我们有这样的一年)的 gannen 表示法比标准 java 得到更好的支持(您必须使用自定义地图再次应用冗长的解决方法)。