我正在使用 PEG 解析器来完成您想要的操作(稍后可能会将其作为单独的答案发布),当时我注意到有一个非常简单的算法,可以很好地处理英语、西班牙语和阿拉伯语中常见的数字形式。至少是德语。
例如,使用英语时,您需要一个字典,以明显的方式将单词映射到值:
"one" -> 1, "two" -> 2, ... "twenty" -> 20,
"dozen" -> 12, "score" -> 20, ...
"hundred" -> 100, "thousand" -> 1000, "million" -> 1000000
...等等
算法就是:
total = 0
prior = null
for each word w
v <- value(w) or next if no value defined
prior <- case
when prior is null: v
when prior > v: prior+v
else prior*v
else
if w in {thousand,million,billion,trillion...}
total <- total + prior
prior <- null
total = total + prior unless prior is null
例如,其进展如下:
total prior v unconsumed string
0 _ four score and seven
4 score and seven
0 4
20 and seven
0 80
_ seven
0 80
7
0 87
87
total prior v unconsumed string
0 _ two million four hundred twelve thousand eight hundred seven
2 million four hundred twelve thousand eight hundred seven
0 2
1000000 four hundred twelve thousand eight hundred seven
2000000 _
4 hundred twelve thousand eight hundred seven
2000000 4
100 twelve thousand eight hundred seven
2000000 400
12 thousand eight hundred seven
2000000 412
1000 eight hundred seven
2000000 412000
1000 eight hundred seven
2412000 _
8 hundred seven
2412000 8
100 seven
2412000 800
7
2412000 807
2412807
等等。我并不是说它是完美的,但对于快速和肮脏的情况来说,它做得相当好。
在编辑时处理您的特定列表:
- 基数/名义或序数:“一”和“第一”--只需将它们放入字典中即可
- 英语/英国语:“四十”/“四十”--ditto
- 数百/数千:
2100 -> “二十一百”还有“两千一百”——按原样工作
- 分隔符:“1152”,也可以是“1152”或“1152”等等——只需将“下一个单词”定义为与已定义单词匹配的最长前缀,或者如果没有,则定义为下一个非单词,作为开始
- 口语:“三十多岁”——works
- 片段:“三分之一”、“五分之二”--呃,还没……
- 通用名称:“一打”、“一半”——作品;你甚至可以做“六打”之类的事情
数字 6 是唯一一个我没有现成答案的问题,这是因为序数词和分数之间的歧义(至少在英语中),再加上我最后一杯咖啡是many几个小时前。