在 PHP 中将单词转换为数字
我正在尝试将写成单词的数值转换为整数。例如,“iPhone有二十三万七百八十三个应用程序”就会变成“iPhone作为230783应用程序”。
在我开始编码之前,我想知道是否存在此转换的任何函数/代码。
我正在尝试将写成单词的数值转换为整数。例如,“iPhone有二十三万七百八十三个应用程序”就会变成“iPhone作为230783应用程序”。
在我开始编码之前,我想知道是否存在此转换的任何函数/代码。
有很多页面讨论从数字到单词的转换。相反的方向没有那么多。我能找到的最好的是Ask Yahoo上的一些伪代码。请参阅 http://answers.yahoo.com/question/index?qid=20090216103754AAONnDz 以获取一个不错的算法:
好吧,总的来说,你正在做两件事:查找标记(转换为数字的单词)和应用语法。简而言之,您正在为非常有限的语言构建解析器。
您需要的令牌是:
力量:千,百万,十亿
:百十
:二十,三十...九十
单位:一个,两个,三个,...九,
特别:十,十一,十二,...十九(删除任何“和”,因为它们毫无意义。将连字符分成两个标记。即六十五应处理为“六十”“五”)
对字符串进行标记后,从右向左移动。
从右边抓取所有令牌,直到你击中一个POWER或整个字符串。
解析这些模式的停止点之后的令牌:
特殊
十
个单位
十个单位
百
个单位 百个
单位 百个单位 百
个单位 百个单位 百个单位
百个单位(这假设“一千七百”在这个语法中是不允许的)
这将为您提供号码的最后三位数字。
如果你停在整个字符串上,你就完成了。
如果停在某个电源,请在步骤 1 处重新开始,直到达到更高的功率或整个字符串。
老问题,但对于其他遇到这个问题的人,我今天必须写一个解决方案。以下内容对John Kugelman描述的算法采取了一种模糊相似的方法,但不适用于严格的语法;因此,它将允许一些奇怪的排序,例如,“十万和一百万”仍将产生与“一百万和十万”(1,100,000)相同的排序。无效位(例如拼写错误的数字)将被忽略,因此考虑无效字符串的输出是未定义的。
在user132513对joebert答案的评论之后,我使用Pear的Number_Words来生成测试系列。以下代码在 0 到 5,000,000 之间的数字上得分为 100%,然后在 0 到 10,000,000 之间的 100,000 个数字的随机样本上得分为 100%(在整个 100 亿系列上运行需要很长时间)。
/**
* Convert a string such as "one hundred thousand" to 100000.00.
*
* @param string $data The numeric string.
*
* @return float or false on error
*/
function wordsToNumber($data) {
// Replace all number words with an equivalent numeric value
$data = strtr(
$data,
array(
'zero' => '0',
'a' => '1',
'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',
'fourty' => '40', // common misspelling
'fifty' => '50',
'sixty' => '60',
'seventy' => '70',
'eighty' => '80',
'ninety' => '90',
'hundred' => '100',
'thousand' => '1000',
'million' => '1000000',
'billion' => '1000000000',
'and' => '',
)
);
// Coerce all tokens to numbers
$parts = array_map(
function ($val) {
return floatval($val);
},
preg_split('/[\s-]+/', $data)
);
$stack = new SplStack; // Current work stack
$sum = 0; // Running total
$last = null;
foreach ($parts as $part) {
if (!$stack->isEmpty()) {
// We're part way through a phrase
if ($stack->top() > $part) {
// Decreasing step, e.g. from hundreds to ones
if ($last >= 1000) {
// If we drop from more than 1000 then we've finished the phrase
$sum += $stack->pop();
// This is the first element of a new phrase
$stack->push($part);
} else {
// Drop down from less than 1000, just addition
// e.g. "seventy one" -> "70 1" -> "70 + 1"
$stack->push($stack->pop() + $part);
}
} else {
// Increasing step, e.g ones to hundreds
$stack->push($stack->pop() * $part);
}
} else {
// This is the first element of a new phrase
$stack->push($part);
}
// Store the last processed part
$last = $part;
}
return $sum + $stack->pop();
}