algorithm - 如何从写成单词的数字中读取值?

标签 algorithm language-agnostic parsing numbers nlp

众所周知,数字既可以用数字书写,也可以用它们的名字来称呼。虽然有很多将 123 转换为 123 的示例,但我找不到如何将其反过来转换的好示例。

一些注意事项:

  1. 基数/名义或序数:“一”和“第一”
  2. 常见的拼写错误:“forty”/“fourty”
  3. 百/千:2100 -> “二百一百”还有“两千一百”
  4. 分隔符:“1152”,还有“1152”或“1152”等等
  5. 俗语:“三十多岁”
  6. 分数:“三分之一”、“五分之二”
  7. 常用名称:“一打”、“一半”

可能还有更多尚未列出的注意事项。 假设算法需要非常稳健,甚至可以理解拼写错误。

我应该阅读哪些领域/论文/研究/算法来学习如何编写所有这些内容? 信息在哪里?

PS: My final parser should actually understand 3 different languages, English, Russian and Hebrew. And maybe at a later stage more languages will be added. Hebrew also has male/female numbers, like "one man" and "one woman" have a different "one" — "ehad" and "ahat". Russian also has some of its own complexities.

Google 在这方面做得很好。例如:

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

等等。我并不是说它是完美的,但对于一个快速而肮脏的人来说,它做得很好。


在编辑时处理您的特定列表:

  1. 基数/名义或序数:“one”和“first”——将它们放入字典中
  2. 英语/英国语:“四十”/“四十”——同上
  3. 数百/数千: 2100 -> "2100"和 "2010"-- 照原样工作
  4. 分隔符:“1152”,还有“1152”或“1152”等等——只需将“下一个词”定义为匹配定义词的最长前缀,或者如果没有的话,直到下一个非单词开始
  5. 俗语:“三十多岁”——有效
  6. 片段:“三分之一”、“五分之二”——呃,还没有......
  7. 常用名称:“一打”、“一半”——有效;你甚至可以做“半打”之类的事情

第 6 号是唯一一个我没有现成答案的,那是因为序数和分数之间的歧义(至少在英语中)加上我最后一杯咖啡 很多 几个小时前。

关于algorithm - 如何从写成单词的数字中读取值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70161/

相关文章:

javascript - 如何从加权图中的顶点找到长度为 k 的最短路径?

python - 算法 : Square root optimization

json - VBA-Json 解析嵌套 Json

c - C 中的 HTML 标签检查

algorithm - 从二叉搜索树构建 AVL 树

algorithm - O(n log n) 是否有简写术语?

math - 计算两个整数的最小公倍数的最有效方法是什么?

algorithm - 空间(槽)优化算法

validation - 验证假名输入

java - 接受 05/05/1999 和 5/5/1999 等的日期时间解析