用Java解析法语日期
我得到以下日期字符串
10 juil 2014
用法语查看一年中几个月的名字,我看到juil
是juillet
的缩写,7月用英语表示。
我尝试使用具有French
区域设置的SimpleDateFormat
来解析它:
System.out.println(new SimpleDateFormat("dd MMM yyyy", Locale.FRENCH).parse("11 juil 2014"));
但它引发了一个例外
java.text.ParseException: Unparseable date: "11 juil 2014" at java.text.DateFormat.parse(DateFormat.java:357)
然后我尝试在月份名称后面添加一个句点
System.out.println(new SimpleDateFormat("dd MMM yyyy", Locale.FRENCH).parse("11 juil. 2014"));
现在我得到以下输出
Fri Jul 11 00:00:00 EDT 2014
因此看起来我需要一个句号,但是当我尝试解析三月日期( mars
)时,如果添加句点,则无法识别。
我应该如何解析法国日期? 我可以通过两次传递:首先是一段时间,然后没有一段时间,并希望其中一个能够做到这一点,但有更好的方法吗?
在@ tobias_k的评论的基础上,这里的代码将在日期字符串中找到任何月份,其中法语短月缩写预计以句号结束但不是,并用包括句点的正确缩写替换它。
import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.text.DateFormatSymbols; public String fixFrenchMonths(String date) { for (String mois : DateFormatSymbols .getInstance(Locale.FRENCH).getShortMonths()) { if (mois.endsWith(".")) { Pattern sansDot = Pattern.compile("(" + Pattern.quote(mois.substring(0, mois.length()-1)) + "(?!\\.))"); Matcher matcher = sansDot.matcher(date); if (matcher.find()) { date = matcher.replaceFirst(mois); } } } return date; }
注意:“mois”是法语“月”,“sansDot”表示“withoutDot”。 或许,这可能是一件小事太聪明了。 它使用零宽度负前瞻,以确保它不会替换已包含点的缩写。 它还对DateFormatSymbols
的数据使用Pattern.quote
。 这可能是过度的,因为我们不希望包含任何正则表达式字符的字符(除了我们剥离的点本身除外),但是当从某些我们无法控制的地方传递数据时,它可能比对不起更安全进入Pattern.compile
。
在法语中,缩写的月份名称具有句点。
请参阅耶鲁大学图书馆的这一页,这是几个月名称的缩写 。 列出几十种语言。
“火星”是三月的全名(四个字母)。 这个名字很短,不需要缩写。 没有缩写,所以没有句号。 同样的“mai”(五月),“juin”(六月)和août(八月)。
另外,您可能已经注意到,第一个字母是法语小写但英文大写。
乔达时间
我在Mac OS X Mountain Lion的Java 8中的Joda-Time 2.4中尝试过这个。 [跳转到java.time,Joda-Time的替换]
LocalDate localDate = DateTimeFormat.forPattern( "dd MMM yyyy" ).withLocale( java.util.Locale.FRENCH ).parseLocalDate( "10 juil 2014" );
同样的问题:缺少期间
juillet
和juil.
成功解析为法语,但juil
失败并抛出exception。 月份缩写预计有一个句点终止符。
解决方法:插入句点
让我们使用substring
和lastIndexOf
来撕开字符串,添加句点,然后重建字符串。
测试字符串是否包含:“janv”,“févr”,“avr”,“juil”,“sept”,“oct”,“nov”,“déc”。 请注意,如果您获得具有完整月份名称而不是缩写的字符串,则使用双方空格。
String inputRaw = "10 juil 2014"; int indexOfSecondSpace = inputRaw.lastIndexOf( " " ); String input = inputRaw.substring( 0, indexOfSecondSpace ) + "." + inputRaw.substring( indexOfSecondSpace ); DateTimeFormatter formatter = DateTimeFormat.forPattern( "dd MMM yyyy" ).withLocale( java.util.Locale.FRENCH ); LocalDate localDate = formatter.parseLocalDate( input ); System.out.println( inputRaw + " → " + input + " → " + localDate );
跑步的时候。
10 juil 2014 → 10 juil. 2014 → 2014-07-10
或者调用replace
来替换:
- “janv”→“janv。”
- “févr”→“févr”。
- “avr”→“avr。”
- “juil”→“juil”。
- “9月”→“9月”。
- “oct”→“oct。”
- “nov”→“nov。”
- “déc”→“déc。”
完整性检查
在现实世界中,我会添加一些健全性检查以确保输入符合我们的期望,例如在中间有两个空格而在开头或结尾没有空格。
java.time
Java 8及更高版本附带内置的java.time框架。 这些新类取代了旧的java.util.Date/.Calendar和相关的类,这些类已被certificate设计糟糕,令人困惑且麻烦。 新的java.time类受Joda-Time的启发,由JSR 310定义,由ThreeTen-Extra项目扩展,在Oracle Tutorial中解释,并向后移植到Java 6和7以及向后移植到Android 。
java.time类包含方便的Month
枚举 。 getDisplayName
生成本地化的月份名称。
类似地, DateTimeFormatter
类也生成本地化文本。 调用ofLocalized…
方法。
System.out.println ( "US | Québec | France" ); for ( Month month : Month.values () ) { TextStyle style = TextStyle.SHORT; String us = month.getDisplayName ( style , Locale.US ); String quebec = month.getDisplayName ( style , Locale.CANADA_FRENCH ); String france = month.getDisplayName ( style , Locale.FRANCE ); System.out.println ( us + " | " + quebec + " | " + france ); }
我们在java.time中获得与Joda-Time中相同的行为: 在法语中,缩写的月份具有句点。 月份名称完全是小写的。
US | Québec | France Jan | janv. | janv. Feb | févr. | févr. Mar | mars | mars Apr | avr. | avr. May | mai | mai Jun | juin | juin Jul | juil. | juil. Aug | août | août Sep | sept. | sept. Oct | oct. | oct. Nov | nov. | nov. Dec | déc. | déc.
- kafka.consumer.SimpleConsumer:由于套接字错误而重新连接:java.nio.channels.ClosedChannelException
- 在java变量参数列表中至少需要一个元素
- 如何在Android中暂停Thread的消息队列?
- Android:java.lang.NoClassDefFoundError
- 在AndroidKeyStore密钥生成期间出现IllegalArgumentException(Unparseable date)
- 检索项目的父项时出错:找不到与给定名称“Theme.AppCompat.Light”匹配的资源。 我的R.java失踪了
- queue.yaml无法在App引擎中工作(开发)
- 如何获取捕获图像的URL?
- javax.crypto在不同版本的Android OS中的工作方式不同?
- 为什么方法参数重新分配给局部变量?
- 如果不覆盖hashCode(),HashSet允许重复项目插入