正如我们所知道的数字可以写在数字,或者叫他们的名字。同时有很多实例中可以找到,其中123到一百二十三个,我不能找到很好的例子如何转换的另一方式。

一些注意事项:

  1. 红衣主教/名义或顺序:"一"和"第一"
  2. 共同拼写错误:"四"/"四"
  3. 数百/千:2100->"二十一百"并且"二千一百"
  4. 分离器:"十一百五十二",但也"elevenhundred fiftytwo"或"十一百五十二个"和诸如此类的东西
  5. 俗语:"第三十的东西"
  6. 部分:'三分之一','的两个五分之二的'
  7. 常见的名称:'一个十','一半'

并且有可能更需要注意的可能尚未列出。假设算法需要非常强大,甚至理解的拼写错误。

什么领域/文件/研究/算法应当我读了解如何编写这一切?哪里是信息?

PS:我的最后分析器实际上应该明白3种不同的语言、英语、俄语以及希伯来语。也许在稍后阶段更多语言,将增加。希伯来文的也有男性/女性的数字,比如"个人"和"一个女人"有一个不同的"一个"—"ehad"和"理".俄罗斯还有一些其自身的复杂性。

谷歌的一项伟大的工作。例如:

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)

有帮助吗?

解决方案

我是玩弄一个挂分析程序做什么样的你想(和可后,作为一个单独的答复以后)当我注意到,有一个非常简单的算法,没有一个非常好的工作与常见的形式的数字英语、西班牙和德国,在非常少。

工作与英例如,需要一个典地图话的价值观显而易见的方式:

"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. 红衣主教/名义或顺序:"一"和"第一"-- 只是把它们放在字典中
  2. 英文/英国:"四"/"四"-- 同上
  3. 数百/千:2100->"二十一百"并且"二千一百"-- 作为是
  4. 分离器:"十一百五十二",但也"elevenhundred fiftytwo"或"十一百五十二个"和诸如此类的东西-- 只是定义"下一个单词"是最长的前缀相匹配的一定义的字,或者到下一个非词,如果没有这样做,因为一开始
  5. colloqialisms:"第三十什么"-- 工作
  6. 片段:'三分之一','的两个五分之二的'-- 呃,还没有...
  7. 常见的名称:'一个十','一半'-- 工作;你甚至可以做的东西像"半打"

6号是唯一一个我没有准备好的答案,这是因为的含糊之间的序号和馏分(英文中的至少)加入事实上,我的最后一杯咖啡 很多 小时前。

其他提示

这不是一个容易的问题,我不知道图书馆做到这一点。我可能会坐下来写这样的事情一段时间。我会做它在序言中,Java或Haskell,虽然。我可以看到,有几个问题:

  • 标记:有时,数字都写一千一百五十二个,但我已经看到elevenhundred fiftytwo或十一百五十二和诸如此类的东西。一个就要进行一次调查在何种形式实际上是在使用。这可能特别棘手,用希伯来语。
  • 拼写错误:这不是很难.你有一个数量有限的单词,并且一点Levenshtein-distance魔法应该可以做到。
  • 替代形式,就像你已经提到的,存在。这包括序号/基数,以及第四十/四十和...
  • ...常见的名称或者通常使用的短语和NEs(名的实体)。你想要取30从三十年战争或2从第二次世界大战?
  • 罗马数字吗?
  • Colloqialisms,例如"第三十什么"和"三个欧洲和弹片",这是我不知道如何对待。

如果你有兴趣在这,我可以给它一个镜头,这个周末。我的想法可能是使用UIMA和切分,那么要进一步的标记/消除歧义和最后翻译。可能会有更多的问题,让我们来看看如果我能想出一些更有趣的事情。

对不起,这不是一个真正的答案,只是一个扩展到你的问题。我会让你知道如果我发现/写的东西。

顺便说一句,如果你有兴趣在语义的数字,我只找到一个 有趣的纸 由弗里德里克Moltmann,讨论一些问题有关的逻辑的解释数字。

我有一些代码我写了一段时间前: text2num.这种做一些你想要什么,但它不处理序号。我还没有实际使用这个代码的任何东西,所以它很大程度上未经测试的!

使用的蟒蛇 图案-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)

序号并不适用,因为他们不能参加有意义的方式与其他数语言(...至少在英文)

例如一百和第一、第二十一,等等。

然而,还有另外一个英国/美国的警告字'和'

一百和一(英语) 一百人(美国)

此外,使用"a"意味着一个英文

一千=一千

...在一个侧面说明谷歌的计算器没一个了不起的工作。

一百三万次光速的速度

甚至...

两千一百再加上一打

...跆拳道?!? 一个分数,加上一个十几在罗马数字

这里是一个非常强大的解决方案中。

据我所知这是一个独特的执行方法。

;----------------------------------------------------------------------
; numbers.clj
; written by: Mike Mattie codermattie@gmail.com
;----------------------------------------------------------------------
(ns operator.numbers
  (:use compojure.core)

  (:require
    [clojure.string     :as string] ))

(def number-word-table {
  "zero"          0
  "one"           1
  "two"           2
  "three"         3
  "four"          4
  "five"          5
  "six"           6
  "seven"         7
  "eight"         8
  "nine"          9
  "ten"           10
  "eleven"        11
  "twelve"        12
  "thirteen"      13
  "fourteen"      14
  "fifteen"       15
  "sixteen"       16
  "seventeen"     17
  "eighteen"      18
  "nineteen"      19
  "twenty"        20
  "thirty"        30
  "fourty"        40
  "fifty"         50
  "sixty"         60
  "seventy"       70
  "eighty"        80
  "ninety"        90
})

(def multiplier-word-table {
  "hundred"       100
  "thousand"      1000
})

(defn sum-words-to-number [ words ]
  (apply + (map (fn [ word ] (number-word-table word)) words)) )

; are you down with the sickness ?
(defn words-to-number [ words ]
  (let
    [ n           (count words)

      multipliers (filter (fn [x] (not (false? x))) (map-indexed
                                                      (fn [ i word ]
                                                        (if (contains? multiplier-word-table word)
                                                          (vector i (multiplier-word-table word))
                                                          false))
                                                      words) )

      x           (ref 0) ]

    (loop [ indices (reverse (conj (reverse multipliers) (vector n 1)))
            left    0
            combine + ]
      (let
        [ right (first indices) ]

        (dosync (alter x combine (* (if (> (- (first right) left) 0)
                                      (sum-words-to-number (subvec words left (first right)))
                                      1)
                                    (second right)) ))

        (when (> (count (rest indices)) 0)
          (recur (rest indices) (inc (first right))
            (if (= (inc (first right)) (first (second indices)))
              *
              +))) ) )
    @x ))

这里是一些例子

(operator.numbers/words-to-number ["six" "thousand" "five" "hundred" "twenty" "two"])
(operator.numbers/words-to-number ["fifty" "seven" "hundred"])
(operator.numbers/words-to-number ["hundred"])

我LPC执行你的一些要求(美国只有英文本):

internal mapping inordinal = ([]);
internal mapping number = ([]);

#define Numbers ([\
    "zero"        : 0, \
    "one"         : 1, \
    "two"         : 2, \
    "three"       : 3, \
    "four"        : 4, \
    "five"        : 5, \
    "six"         : 6, \
    "seven"       : 7, \
    "eight"       : 8, \
    "nine"        : 9, \
    "ten"         : 10, \
    "eleven"      : 11, \
    "twelve"      : 12, \
    "thirteen"    : 13, \
    "fourteen"    : 14, \
    "fifteen"     : 15, \
    "sixteen"     : 16, \
    "seventeen"   : 17, \
    "eighteen"    : 18, \
    "nineteen"    : 19, \
    "twenty"      : 20, \
    "thirty"      : 30, \
    "forty"       : 40, \
    "fifty"       : 50, \
    "sixty"       : 60, \
    "seventy"     : 70, \
    "eighty"      : 80, \
    "ninety"      : 90, \
    "hundred"     : 100, \
    "thousand"    : 1000, \
    "million"     : 1000000, \
    "billion"     : 1000000000, \
])

#define Ordinals ([\
    "zeroth"        : 0, \
    "first"         : 1, \
    "second"        : 2, \
    "third"         : 3, \
    "fourth"        : 4, \
    "fifth"         : 5, \
    "sixth"         : 6, \
    "seventh"       : 7, \
    "eighth"        : 8, \
    "ninth"         : 9, \
    "tenth"         : 10, \
    "eleventh"      : 11, \
    "twelfth"       : 12, \
    "thirteenth"    : 13, \
    "fourteenth"    : 14, \
    "fifteenth"     : 15, \
    "sixteenth"     : 16, \
    "seventeenth"   : 17, \
    "eighteenth"    : 18, \
    "nineteenth"    : 19, \
    "twentieth"     : 20, \
    "thirtieth"     : 30, \
    "fortieth"      : 40, \
    "fiftieth"      : 50, \
    "sixtieth"      : 60, \
    "seventieth"    : 70, \
    "eightieth"     : 80, \
    "ninetieth"     : 90, \
    "hundredth"     : 100, \
    "thousandth"    : 1000, \
    "millionth"     : 1000000, \
    "billionth"     : 1000000000, \
])

varargs int denumerical(string num, status ordinal) {
    if(ordinal) {
        if(member(inordinal, num))
            return inordinal[num];
    } else {
        if(member(number, num))
            return number[num];
    }
    int sign = 1;
    int total = 0;
    int sub = 0;
    int value;
    string array parts = regexplode(num, " |-");
    if(sizeof(parts) >= 2 && parts[0] == "" && parts[1] == "-")
        sign = -1;
    for(int ix = 0, int iix = sizeof(parts); ix < iix; ix++) {
        string part = parts[ix];
        switch(part) {
        case "negative" :
        case "minus"    :
            sign = -1;
            continue;
        case ""         :
            continue;
        }
        if(ordinal && ix == iix - 1) {
            if(part[0] >= '0' && part[0] <= '9' && ends_with(part, "th"))
                value = to_int(part[..<3]);
            else if(member(Ordinals, part))
                value = Ordinals[part];
            else
                continue;
        } else {
            if(part[0] >= '0' && part[0] <= '9')
                value = to_int(part);
            else if(member(Numbers, part))
                value = Numbers[part];
            else
                continue;
        }
        if(value < 0) {
            sign = -1;
            value = - value;
        }
        if(value < 10) {
            if(sub >= 1000) {
                total += sub;
                sub = value;
            } else {
                sub += value;
            }
        } else if(value < 100) {
            if(sub < 10) {
                sub = 100 * sub + value;
            } else if(sub >= 1000) {
                total += sub;
                sub = value;
            } else {
                sub *= value;
            }
        } else if(value < sub) {
            total += sub;
            sub = value;
        } else if(sub == 0) {
            sub = value;
        } else {
            sub *= value;
        }
    }
    total += sub;
    return sign * total;
}

嗯,我是太晚上对于这个问题的答案,但是我工作小测试方案,似乎已经非常好了我。我用(简单,但是丑陋的,大)经常表达找到所有的话对我来说。表达如下:

(?<Value>(?:zero)|(?:one|first)|(?:two|second)|(?:three|third)|(?:four|fourth)|
(?:five|fifth)|(?:six|sixth)|(?:seven|seventh)|(?:eight|eighth)|(?:nine|ninth)|
(?:ten|tenth)|(?:eleven|eleventh)|(?:twelve|twelfth)|(?:thirteen|thirteenth)|
(?:fourteen|fourteenth)|(?:fifteen|fifteenth)|(?:sixteen|sixteenth)|
(?:seventeen|seventeenth)|(?:eighteen|eighteenth)|(?:nineteen|nineteenth)|
(?:twenty|twentieth)|(?:thirty|thirtieth)|(?:forty|fortieth)|(?:fifty|fiftieth)|
(?:sixty|sixtieth)|(?:seventy|seventieth)|(?:eighty|eightieth)|(?:ninety|ninetieth)|
(?<Magnitude>(?:hundred|hundredth)|(?:thousand|thousandth)|(?:million|millionth)|
(?:billion|billionth)))

这里显示与行符的格式目的。。

不管怎么说,我的方法来执行这RegEx图像PCRE,然后回读的名为匹配。和它的工作在所有的不同实例,列在这个问题,减去"半数",类型,因为我没有加入他们,但你可以看到,它不会硬要这样做。这解决了很多问题。例如,地址的以下项目,在原来的问题和其他的答案:

  1. 红衣主教/名义或顺序:"一"和"第一"
  2. 共同拼写错误:"四"/"四"(请注意,它并没有明确地解决这个问题,那将是什么你想要做之前,你通过了串到这种分析器。这种分析器看到的这例如"四个一"...)
  3. 数百/千:2100->"二十一百"并且"二千一百"
  4. 分离器:"十一百五十二",但也"elevenhundred fiftytwo"或"十一百五十二个"和诸如此类的东西
  5. colloqialisms:"第三十事"(这也是不完全的解决,为什么是"什么"?好了,这代码中找到这些作为只是"30").**

现在,而不是储存这个怪物一定期表达您的来源,我是在考虑建立这RegEx在运行时,采用类似的如下:

char *ones[] = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve",
  "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"};
char *tens[] = {"", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"};
char *ordinalones[] = { "", "first", "second", "third", "fourth", "fifth", "", "", "", "", "", "", "twelfth" };
char *ordinaltens[] = { "", "", "twentieth", "thirtieth", "fortieth", "fiftieth", "sixtieth", "seventieth", "eightieth", "ninetieth" };
and so on...

容易的部分在这里是我们是仅存的话这一问题。在这种情况下的第六,你会注意到,没有一个入口,因为它只是它的正常数量与日上涨了...但是那些像十二个需要不同的关注。

好了,现在我们有代码,以建立我们(丑)RegEx,现在我们只是执行它在我们的数字符串。

有一件事我会建议,是过滤器,或吃个词"和"。这是不必要的,并且只会导致其他问题。

所以,什么你想要做的就是设置一个功能,通过匹配的名为"数量级"成一个功能,看起来在所有可能的幅度值,并乘以你目前的结果,值的幅度。然后,你创建的一个函数,看起来在"价值"命名的匹配,并返回int(或者任何你都使用),基于价值的发现。

所有的价值比赛都加入到你的结果,同时magnitutde匹配结果乘以mag的价值。因此,两百五十万变得以"2",然后"2*100",然后"200+50",然后"250*1000",结束有250000...

只是为了好玩,我写了一vbScript版本的这个和它的工作很棒所有的例子。现在,它不支持名为相匹配,所以我不得不工作一点更难获得正确的结果,但我得到了它。底线是,如果它是一个"价值"相匹配,将它添加你的蓄积。如果它是一个数量级相匹配,乘你的蓄100,1000,1000000,1000000000,等等。这将为你提供一些相当令人惊异的结果,以及所有您需要做的调整对于像"半数"是把它们添加到你的RegEx,把在码标记,并处理它们。

嗯,我希望这个职位可以帮助别人在那里。如果有人想要,我可以后,通过vbScript伪的代码,我在使用的测试这个,但是,这不是漂亮的码,而不是生产的代码。

如果我可以..什么是最终的语言,这将会写在?C++,或者类似的一个脚本语言?格雷格Hewgill的来源,将很长的路要走在帮助了解如何将所有这些都在一起。

让我知道如果我可以的任何其他帮助。对不起,我只知道英国/美国,所以我不能帮助您与其他语言。

我是转换的序号版本声明从早期的现代化的书籍(例如"第2版","版quarta")到整数和所需的支持对于序号1至100英文和序号1-10在一些浪漫的语言。这里就是我想出了在蟒蛇:

def get_data_mapping():
  data_mapping = {
    "1st": 1,
    "2nd": 2,
    "3rd": 3,

    "tenth": 10,
    "eleventh": 11,
    "twelfth": 12,
    "thirteenth": 13,
    "fourteenth": 14,
    "fifteenth": 15,
    "sixteenth": 16,
    "seventeenth": 17,
    "eighteenth": 18,
    "nineteenth": 19,
    "twentieth": 20,

    "new": 2,
    "newly": 2,
    "nova": 2,
    "nouvelle": 2,
    "altera": 2,
    "andere": 2,

    # latin
    "primus": 1,
    "secunda": 2,
    "tertia": 3,
    "quarta": 4,
    "quinta": 5,
    "sexta": 6,
    "septima": 7,
    "octava": 8,
    "nona": 9,
    "decima": 10,

    # italian
    "primo": 1,
    "secondo": 2,
    "terzo": 3,
    "quarto": 4,
    "quinto": 5,
    "sesto": 6,
    "settimo": 7,
    "ottavo": 8,
    "nono": 9,
    "decimo": 10,

    # french
    "premier": 1,
    "deuxième": 2,
    "troisième": 3,
    "quatrième": 4,
    "cinquième": 5,
    "sixième": 6,
    "septième": 7,
    "huitième": 8,
    "neuvième": 9,
    "dixième": 10,

    # spanish
    "primero": 1,
    "segundo": 2,
    "tercero": 3,
    "cuarto": 4,
    "quinto": 5,
    "sexto": 6,
    "septimo": 7,
    "octavo": 8,
    "noveno": 9,
    "decimo": 10
  }

  # create 4th, 5th, ... 20th
  for i in xrange(16):
    data_mapping[str(4+i) + "th"] = 4+i

  # create 21st, 22nd, ... 99th
  for i in xrange(79):
    last_char = str(i)[-1]

    if last_char == "0":
      data_mapping[str(20+i) + "th"] = 20+i

    elif last_char == "1":
      data_mapping[str(20+i) + "st"] = 20+i

    elif last_char == "2":
      data_mapping[str(20+i) + "nd"] = 20+i

    elif last_char == "3":
      data_mapping[str(20+i) + "rd"] = 20+i

    else:
      data_mapping[str(20+i) + "th"] = 20+i

  ordinals = [
    "first", "second", "third", 
    "fourth", "fifth", "sixth", 
    "seventh", "eighth", "ninth"
  ]

  # create first, second ... ninth
  for c, i in enumerate(ordinals):
    data_mapping[i] = c+1

  # create twenty-first, twenty-second ... ninty-ninth
  for ci, i in enumerate([
    "twenty", "thirty", "forty", 
    "fifty", "sixty", "seventy", 
    "eighty", "ninety"
  ]):
    for cj, j in enumerate(ordinals):
      data_mapping[i + "-" + j] = 20 + (ci*10) + (cj+1)
    data_mapping[i.replace("y", "ieth")] = 20 + (ci*10)

  return data_mapping

尝试

  1. 开HTTP请求"http://www.google.com/search?q="+电话号码+"+in+小数".

  2. 分析结果对于您的号码。

  3. 高速缓存的数量/成果对于课程的请求。

一个地方开始寻找的 gnu get_date lib, ,这可以分析 关于任 英语文本的日期为时间戳。虽然不完全是你在寻找什么,其解决类似的问题可以提供许多有用的线索。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top