用Java解析法语日期

MxL*_*evs 7 java

我得到以下日期字符串

10 juil 2014
Run Code Online (Sandbox Code Playgroud)

用法语查看一年中的月份名称,我看到它juil是英文的juillet7月份的缩写.

我尝试使用解析它SimpleDateFormatFrench区域设置:

System.out.println(new SimpleDateFormat("dd MMM yyyy", Locale.FRENCH).parse("11 juil 2014"));
Run Code Online (Sandbox Code Playgroud)

但它引发了一个例外

java.text.ParseException: Unparseable date: "11 juil 2014"
    at java.text.DateFormat.parse(DateFormat.java:357)
Run Code Online (Sandbox Code Playgroud)

然后我尝试在月份名称后面添加一个句点

System.out.println(new SimpleDateFormat("dd MMM yyyy", Locale.FRENCH).parse("11 juil. 2014"));
Run Code Online (Sandbox Code Playgroud)

现在我得到以下输出

Fri Jul 11 00:00:00 EDT 2014
Run Code Online (Sandbox Code Playgroud)

因此看起来我需要一个句点,但是当我尝试解析March date(mars)时,如果添加句点,则无法识别.

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

Bas*_*que 5

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

请参阅耶鲁大学图书馆的此页面,月份名称的缩写。列出了几十种语言。

“mars”是三月的全称(四个字母)。这个名字很短,不需要缩写。没有缩写,所以没有句号。“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" );
Run Code Online (Sandbox Code Playgroud)

相同的问题:缺少期间

双方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 );
Run Code Online (Sandbox Code Playgroud)

跑的时候。

LocalDate localDate = DateTimeFormat.forPattern( "dd MMM yyyy" ).withLocale( java.util.Locale.FRENCH ).parseLocalDate( "10 juil 2014" );
Run Code Online (Sandbox Code Playgroud)

或致电replace更换:

  • “简”?“一月。”
  • “发烧”?“热。”
  • “avr”?“啊。”
  • “朱尔”?“朱尔。”
  • “七月”?“九月。”
  • “八月”?“十月。”
  • “新”?“十一。”
  • “德克”?“十二月”

完整性检查

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

时间

Java 8 及更高版本带有内置的 java.time 框架。这些新类取代了旧的 java.util.Date/.Calendar 和相关的类,这些类已被证明是设计糟糕、令人困惑和麻烦的。新的 java.time 类受到Joda-Time 的启发,由JSR 310定义,由ThreeTen-Extra项目扩展,在Oracle 教程中解释,向后移植到 Java 6 和 7以及向后移植到 Android

java.time 类包括方便的enum。该生成本月本地化名称。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 );
}
Run Code Online (Sandbox Code Playgroud)

我们在 java.time 中得到与在 Joda-Time 中看到的相同的行为:在法语中,缩写的月份有一个句点。月份名称完全小写。

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 );
Run Code Online (Sandbox Code Playgroud)


Dav*_*rad 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;
    }
Run Code Online (Sandbox Code Playgroud)

注意:“mois”是法语“月”的意思,“sansDot”的意思是“没有点”。也许这有点太聪明了。它使用零宽度负前瞻来确保它不会替换已经包含点的缩写。它还使用Pattern.quote来自 的数据DateFormatSymbols。这可能有点矫枉过正,因为我们不希望包含任何正则表达式元字符(除了点本身,我们将其删除),但是当从我们无法控制的某个地方传递数据时,安全可能比遗憾更好进入Pattern.compile