序数不适用,因为它们不能以有意义的方式与语言中的其他数字(...至少是英语)结合在一起
例如一百一十一,十一秒等等...
但是,还有另一个英美警告:“ and”一词
即
一百一十一(英语)一百一十一(美国)
另外,用“ a”表示英语中的一个
一千=一千
...附带说明,Google的计算器在这方面做得非常出色。
乃至...
... wtf?!? 比分加上一打罗马数字
0
序数不适用,因为它们不能以有意义的方式与语言中的其他数字(...至少是英语)结合在一起
例如一百一十一,十一秒等等...
但是,还有另一个英美警告:“ and”一词
即
一百一十一(英语)一百一十一(美国)
另外,用“ a”表示英语中的一个
一千=一千
...附带说明,Google的计算器在这方面做得非常出色。
乃至...
... wtf?!? 比分加上一打罗马数字
0
这不是一个容易的问题,而且我知道没有图书馆可以做到这一点。我可能会坐下来尝试写一些这样的东西。不过,我会在Prolog,Java或Haskell中进行操作。据我所知,有几个问题:
如果您对此感兴趣,我可以在本周末试一下。我的想法可能是使用UIMA并对其进行标记化,然后进一步对标记化/消除歧义,最后进行翻译。可能还有更多问题,让我们看看是否可以提出一些更有趣的事情。
抱歉,这还不是真正的答案,只是您问题的延伸。如果我找到/写了一些东西,我会告诉你。
顺便说一句,如果您对数字的语义感兴趣,我刚刚找到了Friederike Moltmann的有趣论文 ,讨论了有关数字逻辑解释的一些问题。
0
您应该记住,欧洲和美国的计数方式有所不同。
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)
0
使用Python pattern-en库:
>>> from pattern.en import number
>>> number('two thousand fifty and a half') => 2050.5
0
这是Clojure中极其强大的解决方案。
AFAIK是一种独特的实现方法。
;----------------------------------------------------------------------
; 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"])
0
我对某些要求的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;
}
0
好吧,对于这个问题的答案,我为时已晚,但是我正在研究一个似乎对我来说效果很好的测试场景。我使用了一个(简单但难看又大的)正则表达式来查找所有适合我的单词。表达式如下:
(?<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)))
此处以换行符显示,用于格式化。
无论如何,我的方法是使用PCRE之类的库执行此RegEx,然后读回命名的匹配项。它可以处理此问题中列出的所有不同示例,减去“ One Half”类型,因为我没有添加它们,但是如您所见,这样做并不难。这解决了很多问题。例如,它解决了原始问题和其他答案中的以下项目:
现在,我没有考虑将正则表达式的怪物存储在您的源代码中,而是考虑在运行时使用以下内容构建此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...
这里最简单的部分是我们只存储重要的单词。在SIXTH的情况下,您会注意到没有条目,因为这只是加TH的正常数字。但是像TWELVE这样的条目需要不同的注意。
好的,现在我们有了构建(丑陋的)RegEx的代码,现在只需对数字字符串执行它即可。
我建议的一件事是过滤或吃掉“ AND”一词。这是没有必要的,只会导致其他问题。
因此,您要做的是设置一个函数,该函数将“ Magnitude”的命名匹配传递给一个函数,该函数查看所有可能的幅度值,并将当前结果乘以那个幅度值。然后,创建一个函数,该函数查看名为match的“ Value”,并根据在此发现的值返回一个int(或您使用的任何值)。
所有VALUE个匹配项都添加到您的结果中,而magnitutde匹配项将结果乘以mag值。因此,二十万变成“ 2”,然后是“ 2 * 100”,然后是“ 200 + 50”,然后是“ 250 * 1000”,最后变成250000 ...
只是为了好玩,我写了一个vbScript版本,它与提供的所有示例都很好用。现在,它不支持命名匹配,因此我不得不更加努力地获得正确的结果,但是我明白了。底线是,如果它是“ VALUE”匹配项,则将其添加为累加器。如果是大小匹配,则将累加器乘以100、1000、1000000、1000000000等。这将为您提供一些非常惊人的结果,而您要做的所有调整(如“一半”)的操作都将它们相加到您的RegEx,为其添加代码标记,并对其进行处理。
好吧,我希望这篇文章能对其他人有所帮助。如果有人愿意,我可以通过vbScript发布用于测试的伪代码,但这不是漂亮的代码,而不是生产代码。
如果可以的话,将使用的最终语言是什么? C ++还是类似脚本语言的东西?格雷格·休吉尔(Greg Hewgill)的资料将有助于理解所有这些因素。
让我知道我是否还有其他帮助。抱歉,我只会说英语/美国语,因此我无法为您提供其他语言的帮助。
0
当我发现有一个非常简单的算法可以很好地处理英文,西班牙文和英文的常见数字形式时,我正在玩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
等等。我并不是说它是完美的,但是对于快速又肮脏的它来说效果很好。
在编辑时处理您的特定列表:
数字6是我唯一没有答案的答案,这是因为普通和分数之间的歧义(至少用英语来说),加之我最后一杯咖啡是在几个小时之前的。
0
众所周知,数字既可以用数字写成,也可以用名字来称呼。尽管有很多将123转换为123的示例,但我找不到如何将123转换为123的良好示例。
一些警告:
而且可能还有更多未列出的警告。假设算法需要非常健壮,甚至可以理解拼写错误。
我应该阅读哪些领域/论文/研究/算法以学习如何编写所有这些内容?信息在哪里?
Google在这方面做得很好。例如:
http://www.google.com/search?q=小数点后加一千+一+一百+五+六+六+四+五+
(反过来也可以http://www.google.com/search?q=999999999999+in+english )