numbers and reminder markers come from the lexicon (V-530)
ruNumerals was a second copy of the number words. It stopped at fifty, had no oblique forms, and disagreed with lexicon_ru_v1.json about its own members, so "к семи" was not the hour "в семь" was. The lexicon now carries the oblique cardinals and numwords.go asks lexicon.Cardinal. "час" and "часу" stay local: they are the hour noun as often as the number one, and nobody counts "час яблок". reminderbody.go built its markers from three inline word lists. Two of them are new lexicon sets, reminder_verbs and parts_of_day, and the day offsets were already there. The alternation helper sorts by length so a longer form wins the regex. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+28
-32
@@ -1,38 +1,34 @@
|
||||
package router
|
||||
|
||||
import "strings"
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
// ruNumerals — spoken numbers as digits, for the clock hours and the minutes
|
||||
// that follow them. Every case ending he might say is listed rather than
|
||||
// stemmed: "в семь", "к семи", "около семи" are three forms of one hour, and a
|
||||
// prefix rule short enough to cover them also matches "семья".
|
||||
"github.com/kami/maven/internal/lexicon"
|
||||
)
|
||||
|
||||
// hourNouns — the two words that are the hour noun as often as they are the
|
||||
// number one. "в час дня" means one o'clock, so rewriting it to "в 1 дня" is
|
||||
// right either way.
|
||||
//
|
||||
// Stops at thirty, which is as far as a spoken time goes ("без двадцати
|
||||
// восемь", "в половине шестого"). Anything larger is said in digits.
|
||||
var ruNumerals = map[string]string{
|
||||
"один": "1", "одного": "1", "одну": "1", "час": "1", "часу": "1",
|
||||
"два": "2", "две": "2", "двух": "2",
|
||||
"три": "3", "трёх": "3", "трех": "3",
|
||||
"четыре": "4", "четырёх": "4", "четырех": "4",
|
||||
"пять": "5", "пяти": "5",
|
||||
"шесть": "6", "шести": "6",
|
||||
"семь": "7", "семи": "7",
|
||||
"восемь": "8", "восьми": "8",
|
||||
"девять": "9", "девяти": "9",
|
||||
"десять": "10", "десяти": "10",
|
||||
"одиннадцать": "11", "одиннадцати": "11",
|
||||
"двенадцать": "12", "двенадцати": "12",
|
||||
"тринадцать": "13", "тринадцати": "13",
|
||||
"четырнадцать": "14", "четырнадцати": "14",
|
||||
"пятнадцать": "15", "пятнадцати": "15",
|
||||
"шестнадцать": "16", "шестнадцати": "16",
|
||||
"семнадцать": "17", "семнадцати": "17",
|
||||
"восемнадцать": "18", "восемнадцати": "18",
|
||||
"девятнадцать": "19", "девятнадцати": "19",
|
||||
"двадцать": "20", "двадцати": "20",
|
||||
"тридцать": "30", "тридцати": "30",
|
||||
"сорок": "40", "сорока": "40",
|
||||
"пятьдесят": "50", "пятидесяти": "50",
|
||||
// They are not cardinals and do not belong in the lexicon's number set: nobody
|
||||
// counts "час яблок". Everything else this file reads comes from
|
||||
// lexicon.Cardinal, which is where the number words live complete, oblique forms
|
||||
// included (Vikunja #530). The table here used to be a second copy that stopped
|
||||
// at fifty and disagreed with the lexicon about its own members.
|
||||
var hourNouns = map[string]string{"час": "1", "часу": "1"}
|
||||
|
||||
// numeralDigit reports the digits a spoken number is written as, for a clock
|
||||
// hour or the minutes after it.
|
||||
func numeralDigit(word string) (string, bool) {
|
||||
if d, ok := hourNouns[word]; ok {
|
||||
return d, true
|
||||
}
|
||||
n, ok := lexicon.Cardinal(word)
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
return strconv.Itoa(n), true
|
||||
}
|
||||
|
||||
// numeralContext — the words that make a numeral a time. A numeral is only
|
||||
@@ -67,7 +63,7 @@ func SpellOutDigits(text string) string {
|
||||
copy(out, toks)
|
||||
for i, tok := range toks {
|
||||
key := strings.ToLower(strings.Trim(tok, ".,!?;:«»\"'"))
|
||||
digit, ok := ruNumerals[key]
|
||||
digit, ok := numeralDigit(key)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user