Подтвердить что ты не робот

Преобразование слов в числа в PHP

Я пытаюсь преобразовать числовые значения, записанные как слова в целые числа. Например, "У iPhone есть двести тридцать тысяч семьсот восемьдесят три приложения" станет "iPhone как 230783 приложений"

Прежде чем начать кодирование, я хотел бы знать, существует ли какая-либо функция/код для этого преобразования.

4b9b3361

Ответ 1

Существует много страниц, посвященных переходу от чисел к словам. Не так много для обратного направления. Лучшее, что я мог найти, - это какой-то псевдокод на Ask Yahoo. См. http://answers.yahoo.com/question/index?qid=20090216103754AAONnDz для хорошего алгоритма:

Ну, в общем, вы делаете две вещи: поиск токенов (слова, которые переводится на цифры) и применение грамматики. Короче говоря, вы создаете парсер для очень ограниченного языка.

Значки, которые вам понадобятся:

ПИТАНИЕ: тыс., млн, млрд.
СТО: сто
ДЕСЯТЬ: двадцать, тридцать... девяносто
UNIT: один, два, три,... девять,
СПЕЦИАЛЬНЫЙ: десять, одиннадцать, двенадцать,... девятнадцать.

(отбрасывать любые "и", так как они бессмысленны. Разделите дефисы на два маркера. Это шестьдесят пять должны обрабатываться как "шестьдесят" "пять" )

После того, как вы пометили свою строку, перейдите от правого к левому.

  • Возьмите все жетоны с ПРАВА, пока не нажмете POWER или целую строку.

  • Разберите маркеры после точки останова для этих паттернов:

    SPECIAL
    ДЕСЯТЬ
    БЛОК
    ДЕСЯТЬ ЕДИНИЦ
    СОЕДИНЕННЫЕ СОТРУДНИКИ
    СОТРУДНИКИ СПЕЦИАЛЬНЫЕ
    ЕДИНИЦА СТО ДЕСЯТЬ
    СОТРУДНИЧНАЯ ЕДИНИЦА

    UNIT COUNEN TEN UNIT

    (Это предполагает, что в этой грамматике не допускается "семнадцать сотен" )

    Это дает вам последние три цифры вашего номера.

  • Если вы остановились на всей строке, вы сделали.

  • Если вы остановились на мощности, начните снова на шаге 1, пока не достигнете более высокой мощности или всей строки.

Ответ 2

Старый вопрос, но для тех, кто еще сталкивался с этим, мне пришлось написать решение для этого сегодня. Ниже приводится смутно подобный подход к алгоритму, описанному Джоном Кугельманом, но не применяется в качестве строгой грамматики; как таковой, он допускает некоторые странные упорядочения, например. "сто тысяч и один миллион" будут по-прежнему производить такие же, как "один миллион и сто тысяч" (1 100 000). Неверные биты (например, номера с ошибками) будут проигнорированы, поэтому рассмотрим вывод на недопустимых строках undefined.

Следуя за комментарием пользователя132513 в ответ на joebert, я использовал Pear Number_Words для создания серии тестов. Следующий код набрал 100% на номера от 0 до 5 000 000, а затем 100% на случайную выборку из 100 000 номеров от 0 до 10 000 000 (она длится дольше, чем для всех 10-миллиардных серий).

/**
 * 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();
}

Ответ 3

Я не тестировал это слишком широко, я более или менее просто работал над ним, пока не увидел, что я ожидал в выходе, но он работает, и анализирует слева направо.

<?php

$str = 'twelve billion people know iPhone has two hundred and thirty thousand, seven hundred and eighty-three apps as well as over one million units sold';

function strlen_sort($a, $b)
{
    if(strlen($a) > strlen($b))
    {
        return -1;
    }
    else if(strlen($a) < strlen($b))
    {
        return 1;
    }
    return 0;
}

$keys = array(
    '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'
);


preg_match_all('#((?:^|and|,| |-)*(\b' . implode('\b|\b', array_keys($keys)) . '\b))+#i', $str, $tokens);
//print_r($tokens); exit;
$tokens = $tokens[0];
usort($tokens, 'strlen_sort');

foreach($tokens as $token)
{
    $token = trim(strtolower($token));
    preg_match_all('#(?:(?:and|,| |-)*\b' . implode('\b|\b', array_keys($keys)) . '\b)+#', $token, $words);
    $words = $words[0];
    //print_r($words);
    $num = '0'; $total = 0;
    foreach($words as $word)
    {
        $word = trim($word);
        $val = $keys[$word];
        //echo "$val\n";
        if(bccomp($val, 100) == -1)
        {
            $num = bcadd($num, $val);
            continue;
        }
        else if(bccomp($val, 100) == 0)
        {
            $num = bcmul($num, $val);
            continue;
        }
        $num = bcmul($num, $val);
        $total = bcadd($total, $num);
        $num = '0';
    }
    $total = bcadd($total, $num);
    echo "$total:$token\n";
    $str = preg_replace("#\b$token\b#i", number_format($total), $str);
}
echo "\n$str\n";

?>

Ответ 5

Вы упомянули некоторую ошибку script, пожалуйста, отметьте один раз в точке зрения разработчика ex: 83139, если вы спросите слова, это даст другой ответ

передать строку, указанную ниже, и проверить все:

"номер автобуса пятнадцать от номера остановки автобуса восемьдесят три тысячи сто тридцать девять"