Kotlin/Java/JVM - Парсинг русских дат типа "28 фев. 2019"

Я не говорю по-русски, поэтому у меня возникают проблемы с проверкой правильности написания месяцев и т. д. Честно говоря, я не совсем уверен, что ввожу текст на русском языке (русский язык определяется переводчиком Google)

У меня есть код на Kotlin, который делает все возможное для анализа дат, указанных в различных форматах и ​​на разных языках. Однако я борюсь с разбором русских дат. Вот соответствующая часть моего кода:

sequenceOf(
  "ru-RU", // Russian
  "sr", // Serbian
).forEach {
  val format = DateTimeFormatter.ofPattern("d MMM. yyyy")
    .withLocale(Locale.forLanguageTag(it))
  try {
    return listOf(LocalDate.parse(dateString, format))
  } catch (e: Exception) {
    //Ignore and move on
  }
}

Этот код правильно анализирует "27 апр. 2018" и "24 мая. 2013", но не работает с "28 фев. 2019".

Что особенного в "28 фев. 2019" и/или как мне правильно разобрать это значение?

Если вы дадите ответы на Java, я могу довольно легко перевести их на Kotlin.


Обновлено: Вот SSCCE в Котлине:

import java.time.LocalDate
import java.time.format.DateTimeFormatter
import java.util.*

println("System.getProperty - " + System.getProperty("java.version"));
println("Runtime.version - " + Runtime.version());

val dateString = "28 фев. 2019"

sequenceOf(
    "ru-RU", // Russian
    "sr", // Serbian
).forEach {
    val format = DateTimeFormatter.ofPattern("d MMM. yyyy")
        .withLocale(Locale.forLanguageTag(it))
    try {
        println("Parse successful - " + LocalDate.parse(dateString, format))
    } catch (e: Exception) {
        println("Parse failed - " + e)
    }
}

Вывод в моей системе:

System.getProperty - 17.0.4.1
Runtime.version - 17.0.4.1+7-b469.62
Parse failed - java.time.format.DateTimeParseException: Text '28 фев. 2019' could not be parsed at index 3
Parse failed - java.time.format.DateTimeParseException: Text '28 фев. 2019' could not be parsed at index 3

🤔 А знаете ли вы, что...
С Java можно создавать мобильные приложения для iOS с использованием фреймворка RoboVM.


2
141
2

Ответы:

Ваш ввод, кажется, имеет неправильную аббревиатуру. Правильная аббревиатура должна быть февр.. Проверьте эту страницу и эту страницу для получения дополнительной информации.

Обходным путем может быть замена ввода правильной аббревиатурой перед его синтаксическим анализом.

public class Main {
    public static void main(String[] args) {
        String input = "28 фев. 2019";
        input = input.replace("фев.", "февр.");

        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("d MMM uuuu",
                Locale.forLanguageTag("ru-RU"));

        System.out.println(LocalDate.parse(input, dtf));
        System.out.println(LocalDate.of(2019, 2, 28).format(dtf));
    }
}

Вывод:

2019-02-28
28 февр. 2019

Решено

Поскольку вы анализируете пользовательский ввод, я считаю, что единственный вариант - нормализовать этот ввод до его разбора - обращение к стандартам здесь не вариант.

В русском языке мы используем родительную форму названия месяца в датах (M(M)+ vs L(L)+ в java DateTimeFormat) и, как правило, краткие формы создаются с использованием приведенных ниже правил (пожалуйста, не путайте это со стандартами программирования, соглашениями, привычками, трюками, UI/UX). направляющие и др.):

  • . (точка) обозначает краткую форму слова (мая. vs мая - первая форма выглядит нелепо, потому что мая является полной формой родительного падежа May, другой случай: июн. vs июня - обе имеют одинаковую длину, но июня является полной формой родительного падежа June)
  • обычно последующий согласный следует сохранять, если за ним следует гласный в полной форме (есть некоторые исключения для двойных согласных) - похоже, ваш случай: фев. vs февр.
  • краткая форма не должна заканчиваться на гласную, й, ь или ъ

Исходя из этого и принимая во внимание возможные ошибки пользователя, опечатки, здравый смысл и привычки программирования, вы потенциально можете столкнуться со следующими «краткими формами родительного падежа» названий месяцев в дикой природе:

  • Январь: янв, янв.
  • Февраль: фев, февр, фев., февр.
  • Март: мар, марта, мар., март.
  • Апрель: апр, апр.
  • Май: мая, мая.
  • Июнь: июн, июня, июн.
  • Июль: июл, июля, июл.
  • Август: авг, авг.
  • Сентябрь: сен, сент, сен., сент.
  • Октябрь: окт, окт.
  • Ноябрь: ноя, нояб, ноя., нояб.
  • Декабрь: дек, дек.