Я пытаюсь преобразовать числовые значения, записанные как слова в целые числа. Например, «iPhone имеет двести тридцать тысяч семьсот восемьдесят три приложения» станет «iPhone в качестве 230783 приложений»,
Прежде чем начать кодирование, я хотел бы знать, существует ли какая-либо функция / код для этого преобразования.
Существует много страниц, посвященных переходу от чисел к словам. Не так много для обратного направления. Лучшее, что я мог найти, – это какой-то псевдокод на Ask Yahoo. См. http://answers.yahoo.com/question/index?qid=20090216103754AAONnDz для хорошего алгоритма:
Ну, в общем, вы делаете две вещи: поиск токенов (слова, которые переводится на цифры) и применение грамматики. Короче говоря, вы создаете парсер для очень ограниченного языка.
Знаки, которые вам понадобятся:
ПИТАНИЕ: тысячи, миллион, миллиард
СТО: сто
ДЕСЯТЬ: двадцать, тридцать … девяносто
UNIT: один, два, три, … девять,
СПЕЦИАЛЬНЫЙ: десять, одиннадцать, двенадцать, … девятнадцать(отбрасывать любые «и», так как они бессмысленны. Разделите дефисы на два токена. Это шестьдесят пять, которые должны обрабатываться как «шестьдесят» «пять»)
После того, как вы обозначили свою строку, перейдите от правого к левому.
Возьмите все жетоны с ПРАВА, пока не нажмете POWER или всю строку.
Разберите токены после точки остановки для этих шаблонов:
ОСОБЫЙ
10
ЕД. ИЗМ
ДЕСЯТЬ ЕДИНИЦ
СОТРУДНИКИ СО СТОРОНЫ
СОТРУДНИКИ СПЕЦИАЛЬНЫЕ
UNIT COUN TEN
СОТРУДНИЧНЫЙ БЛОК
СОЕДИНИТЕЛЬНЫЙ ДЕСЯТЫЙ ЕДИНИЦ(Это предполагает, что «семнадцатьсот» не допускается в этой грамматике)
Это дает вам последние три цифры вашего номера.
Если вы остановились на всей цепочке, вы закончили.
Если вы остановились на мощности, начните снова на шаге 1, пока не достигнете более высокой мощности или всей строки.
Старый вопрос, но для всех, кто сталкивался с этим, мне пришлось написать решение для этого сегодня. Ниже приводится смутно подобный подход к алгоритму, описанному Джоном Кугельманом, но не применяется в качестве строгой грамматики; таким образом, это позволит некоторым странным упорядочениям, например, «сто тысяч и один миллион» будет по-прежнему производить то же самое, что «один миллион и сто тысяч» (1 100 000). Неверные биты (например, номера с ошибками) будут игнорироваться, поэтому следует учитывать, что вывод на недопустимых строках не определен.
Следуя комментарию пользователя132513 о ответе Джобера, я использовал Pear's 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, eg 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 // eg "seventy one" -> "70 1" -> "70 + 1" $stack->push($stack->pop() + $part); } } else { // Increasing step, eg 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(); }
Я не тестировал это слишком широко, я более или менее просто работал над ним, пока не увидел то, что ожидал в выходе, но, похоже, работает, и анализирует слева направо.
<?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"; ?>
Пакет PEAR Numbers_Words
, вероятно, хороший старт: http://pear.php.net/package-info.php?package=Numbers_Words
Вы упомянули некоторый сценарий ошибок, пожалуйста, отметьте один раз в точке зрения разработчика ex: 83139, если вы спросите словами, это даст другой ответ
передайте строку, указанную ниже, и проверьте все:
«автобус номер пятнадцать с автобусной остановки номер восемьдесят три тысячи сто тридцать девять»