在 PHP 中将单词转换为数字

2022-08-30 19:40:28

我正在尝试将写成单词的数值转换为整数。例如,“iPhone有二十三万七百八十三个应用程序”就会变成“iPhone作为230783应用程序”。

在我开始编码之前,我想知道是否存在此转换的任何函数/代码。


答案 1

有很多页面讨论从数字到单词的转换。相反的方向没有那么多。我能找到的最好的是Ask Yahoo上的一些伪代码。请参阅 http://answers.yahoo.com/question/index?qid=20090216103754AAONnDz 以获取一个不错的算法:

好吧,总的来说,你正在做两件事:查找标记(转换为数字的单词)和应用语法。简而言之,您正在为非常有限的语言构建解析器。

您需要的令牌是:

力量:千,百万,十亿
:百十
:二十,三十...九十
单位:一个,两个,三个,...九,
特别:十,十一,十二,...十九

(删除任何“和”,因为它们毫无意义。将连字符分成两个标记。即六十五应处理为“六十”“五”)

对字符串进行标记后,从右向左移动。

  1. 从右边抓取所有令牌,直到你击中一个POWER或整个字符串。

  2. 解析这些模式的停止点之后的令牌:

    特殊

    个单位
    十个单位

    个单位 百个
    单位 百个单位 百
    个单位 百个单位 百个单位
    百个单位

    (这假设“一千七百”在这个语法中是不允许的)

    这将为您提供号码的最后三位数字。

  3. 如果你停在整个字符串上,你就完成了。

  4. 如果停在某个电源,请在步骤 1 处重新开始,直到达到更高的功率或整个字符串。


答案 2

老问题,但对于其他遇到这个问题的人,我今天必须写一个解决方案。以下内容对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();
}

推荐