用Java解析法语日期

时间:2014-07-28 18:07:26

标签: java

我获得以下日期字符串

10 juil 2014

用法语查看一年中的月份名称,我看到juiljuillet的缩写,用英语表示7月。

我尝试使用带有SimpleDateFormat区域设置的French来解析它:

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)时,如果添加句点,则无法识别。

我应该如何解析法国日期?我可以通过两次传递:第一次有一段时间,然后没有一段时间,并希望其中一个能做到这一点,但有更好的方法吗?

2 个答案:

答案 0 :(得分:1)

在@ 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"意味着没有多少"。或许,这可能是一件小事太聪明了。它使用零宽度负前瞻来确保它不会替换已经包含点的缩写。它还对来自Pattern.quote的数据使用DateFormatSymbols。这可能是矫枉过正,因为我们不希望包含任何正则表达式字符的字符(除了我们剥离的点本身),但是当从某些字符传递数据时,它可能比对不起更安全我们无法控制Pattern.compile

答案 1 :(得分:1)

在法语中,缩写的月份名称有一个句号。

耶鲁大学图书馆查看此页面,Abbreviations of the Names of the Months。列出几十种语言。

“mars”是March的全名(四个字母)。这个名字很短,不需要缩写。没有缩写,所以没有句号。同样的“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" );

同样的问题:缺少期限

juilletjuil.都成功解析为法语,但juil失败并抛出异常。月份缩写预计会有句号终止符。

解决方法:插入期间

让我们使用substringlastIndexOf拆分字符串,添加句点,然后重建字符串。

测试字符串是否包含:“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。”
  • “sept”→“sept。”
  • “oct”→“oct。”
  • “nov”→“nov。”
  • “déc”→“déc。”

完整性检查

在现实世界中,我会添加一些健全性检查,以确保输入符合我们的期望,例如在中间有两个空格,在开头或结尾没有空格。

java.time

Java 8及更高版本内置了java.time框架。这些新类取代了旧的java.util.Date/.Calendar和相关的类,这些类已被证明设计糟糕,令人困惑且麻烦。新的java.time类受Joda-Time的启发,由JSR 310定义,由ThreeTen-Extra项目扩展,在Oracle Tutorialbackported to Java 6 & 7中进行了解释为backported to Android

java.time类包括方便的Month enumgetDisplayName生成本地化的月份名称。

同样,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.
相关问题