众所周知,数字可以用数字写成,也可以用它们的名字来表示.虽然有很多例子可以将123转换成123,但我找不到如何以相反的方式转换它的好例子.
一些警告:
基数/名义或序数:"一"和"第一"
常见的拼写错误:"四十"/"十四"
数百/数千:2100 - >"二十一",还有"二千一百"
分隔符:"十一二五二",还有"十一五十二"或"十一二十二"等等
口语:"三十多岁"
分数:'三分之一','五分之二'
俗名:'一打','一半'
可能还有更多可能尚未列出的警告.假设算法需要非常健壮,甚至可以理解拼写错误.
我应该阅读哪些领域/论文/研究/算法来学习如何写这些?信息在哪里?
PS:我的最终解析器应该真正理解3种不同的语言,英语,俄语和希伯来语.也许在稍后阶段会添加更多语言.希伯来语也有男/女数字,如"一个男人"和"一个女人"有不同的"一个" - "ehad"和"ahat".俄罗斯也有一些自己的复杂性.
谷歌在这方面做得很好.例如:
http://www.google.com/search?q=two+thousand+and+one+hundred+plus+five+dozen+and+four+fifths+in+decimal
(反过来也可以http://www.google.com/search?q=999999999999+in+english)
当我注意到有一个非常简单的算法可以很好地处理英语,西班牙语和英语中的常见数字形式时,我正在玩一个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
等等.我并不是说这是完美的,但是对于快速而肮脏的事情来说它确实很好.
在编辑时解决您的特定列表:
基数/名义或序数:"一"和"第一" - 只需将它们放入字典中
英语/英语:"fourty"/"forty" - 同上
数百/数千:2100 - >"二十一",还有"二千一百" - 按原样工作
分隔符:"十一二百二十二",还有"十一五十二"或"十一二百五十二"等等 - 只是将"下一个单词"定义为匹配定义单词的最长前缀,或者直到下一个单词如果没有,那就是非单词,一开始
colloqialisms:"三十多岁" - 作品
碎片:"三分之一","五分之二" - 呃,还没......
俗名:'打打','半' - 作品; 你甚至可以做"半打"之类的事情
6号是唯一一个我没有准备好答案的人,这是因为序数和分数之间的模糊性(至少在英语中)增加了我的最后一杯咖啡在几个小时前的事实.
我有一些我刚才写的代码:text2num.这可以做你想要的一些,除了它不处理序数.我实际上并没有使用这个代码,所以它基本上没有经过测试!
这不是一个容易的问题,我知道没有图书馆可以做到这一点.我可能会坐下来尝试写一些这样的东西.不过,我会在Prolog,Java或Haskell中做到这一点.据我所知,有几个问题:
令牌化:有时,数字写成1125,但我已经看过十一五十二或十一点五十二等等.人们必须对实际使用的形式进行调查.这对希伯来语来说可能特别棘手.
拼写错误:这不是那么难.你的单词数量有限,而Levenshtein距离魔法应该可以做到这一点.
存在替代形式,如您已经提到的那样.这包括序数/基数,以及四十四十和......
...通用名称或常用短语和NE(命名实体).你想从三十年战争中抽取30或从第二次世界大战中抽取2吗?
罗马数字呢?
口语,如"三十多岁"和"三欧元和弹片",我不知道该如何对待.
如果你对此感兴趣,我可以在本周末试一试.我的想法可能是使用UIMA并使用它进行标记,然后继续进行标记化/消除歧义并最终翻译.可能会有更多问题,让我们看看我是否可以提出一些更有趣的事情.
对不起,这还不是一个真正的答案,只是你问题的扩展.如果我发现/写东西,我会告诉你的.
顺便说一句,如果你对数字的语义感兴趣,我刚刚发现了Friederike Moltmann的一篇有趣的论文,讨论了有关数字逻辑解释的一些问题.
使用Python pattern-en库:
>>> from pattern.en import number >>> number('two thousand fifty and a half') => 2050.5
你应该记住,欧洲和美国的数量不同.
One Thousand One Million One Thousand Millions (British also use Milliard) One Billion One Thousand Billions One Trillion One Thousand Trillions
这是一个小参考.
查看差异的简单方法如下:
(American counting Trillion) == (European counting Billion)