【问题标题】:Parsing french dates in Java [duplicate]在Java中解析法国日期[重复]
【发布时间】:2014-07-28 18:07:25
【问题描述】:

我得到以下日期字符串

10 juil 2014

在法语中查找一年中月份的名称,我看到juiljuillet的缩写,在英语中指的是七月。

我尝试使用 SimpleDateFormatFrench 语言环境来解析它:

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

所以看起来我需要一个句号,但是当我尝试解析 3 月日期 (mars) 时,如果添加句号,则无法识别。

我应该如何解析法国日期?我可以分两次完成:第一次有句号,然后没有句号,希望其中一个能成功,但有更好的方法吗?

【问题讨论】:

  • 您可能需要维护一个table,并使用法语月份。如果您的日期使用缩写,请添加句点,否则 - 不要。
  • 另见DateFormatSymbols.getInstance(Locale.FRENCH).getShortMonths()。一些短名称甚至带有重音符号。
  • 也许法语缩写的月份名称必须有句点?
  • @tobias_k 谢谢,现在我只是按照 PM77-1 的建议对地图进行硬编码,并根据需要进行转换。似乎是一个灵活的解决方案,因为我没有太多的示例数据可以使用。

标签: java


【解决方案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.”
  • “七月”→“七月。”
  • “九月”→“九月”
  • “八月”→“八月”
  • “十一月”→“十一月”
  • “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 类包括方便的MonthenumgetDisplayName 生成月份的本地化名称。

同样,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.

【讨论】:

  • 亲爱的投反对票的人:请在投反对票的同时留下建设性的批评意见。
【解决方案2】:

基于@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”的意思是“没有点”。也许这有点太聪明了。它使用零宽度的负前瞻来确保它不会替换已经包含点的缩写。它还对来自DateFormatSymbols 的数据使用Pattern.quote。这可能是矫枉过正,因为我们不希望包含任何作为正则表达式元字符的字符(除了点本身,我们将其剥离),但从我们无法控制的某个地方传递数据时,它可能比抱歉更安全进入Pattern.compile

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-22
    • 1970-01-01
    相关资源
    最近更新 更多