— Как читать значения из чисел, записанных словами?
Что ж, я слишком поздно ответил на этот вопрос, но я работал над небольшим тестовым сценарием, который, похоже, сработал для меня очень хорошо. Я использовал (простое, но уродливое и большое) регулярное выражение, чтобы найти все слова для меня. Выражение выглядит следующим образом:
(?<Значение>(?:ноль)|(?:один|первый)|(?:два|второй)|(?:три|третий)|(?:четыре|четвертый) | (?:пять|пятый)|(?:шесть|шестой)|(?:семь|седьмой)|(?:восемь|восьмой)|(?:девять|девятый)| (?:десять|десятая)|(?:одиннадцать|одиннадцатая)|(?:двенадцать|двенадцатая)|(?:тринадцать|тринадцатая)| (?:четырнадцать|четырнадцатый)|(?:пятнадцать|пятнадцатый)|(?:шестнадцать|шестнадцатый)| (?:семнадцать|семнадцатый)|(?:восемнадцать|восемнадцатый)|(?:девятнадцать|девятнадцатый)| (?:двадцать|двадцатый)|(?:тридцать|тридцатый)|(?:сорок|сороковой)|(?:пятьдесят|пятидесятый)| (?:шестьдесят|шестидесятая)|(?:семьдесят|семидесятая)|(?:восемьдесят|восьмидесятая)|(?:девяносто|девяностая)| (?<Величина>(?:сотня|сотая)|(?:тысяча|тысячная)|(?:миллион|миллионная)| (?:миллиард|миллиард)))
Здесь показано с разрывами строк для целей форматирования.
В любом случае, мой метод состоял в том, чтобы выполнить это регулярное выражение с библиотекой, такой как PCRE, а затем прочитать именованные совпадения. И это работало на всех различных примерах, перечисленных в этом вопросе, за исключением типов «Одна половина», поскольку я их не добавлял, но, как вы можете видеть, это было бы несложно сделать. Это решает множество проблем. Например, он касается следующих элементов исходного вопроса и других ответов:
- кардинальное/номинальное или порядковое: «один» и «первый»
- распространенных орфографических ошибок: «сорок»/«сорок» (Обратите внимание, что это ЯВНО не рассматривается, это было бы то, что вы хотели бы сделать, прежде чем передать строку этому синтаксическому анализатору. Этот синтаксический анализатор видит этот пример как «ЧЕТЫРЕ» …)
- сотни/тысячи: 2100 -> «двадцать сто», а также «две тысячи сто»
- разделители: «одиннадцатьсот пятьдесят два», а также «одиннадцатьсот пятьдесят два» или «одиннадцатьсот пятьдесят два» и еще много чего
- разговорные выражения: «тридцать с чем-то» (Это также НЕ ПОЛНОСТЬЮ адресовано, как то, что ТАКОЕ «что-то»? Ну, этот код находит это число как просто «30»). **
Теперь вместо того, чтобы хранить это чудовище регулярного выражения в вашем исходном коде, я рассматривал возможность создания этого регулярного выражения во время выполнения, используя что-то вроде следующего:
char *ones[] = {"zero", "one", " два", "три", "четыре", "пять", "шесть", "семь", "восемь", "девять", "десять", "одиннадцать", "двенадцать", «тринадцать», «четырнадцать», «пятнадцать», «шестнадцать», «семнадцать», «восемнадцать», «девятнадцать»}; char *tens[] = {"", "", "двадцать", "тридцать", "сорок", "пятьдесят", "шестьдесят", "семьдесят", "восемьдесят", "девяносто"}; char *ordinalones[] = { "", "первый", "второй", "третий", "четвертый", "пятый", "", "", "", "", "", "", "двенадцатый " }; char *ordinaltens[] = { "", "", "двадцатый", "тридцатый", "сороковой", "пятидесятый", "шестидесятый", "семидесятый", "восьмидесятый", "девяностый" }; и так далее...
Самое простое здесь то, что мы сохраняем только те слова, которые имеют значение. В случае с ШЕСТЫМ вы заметите, что для него нет записи, потому что это просто обычный номер с добавленным TH. .. Но такие, как ДВЕНАДЦАТЬ, требуют особого внимания.
Итак, теперь у нас есть код для создания нашего (уродливого) RegEx, теперь мы просто выполняем его на наших числовых строках.
Одна вещь, которую я бы порекомендовал, это отфильтровать или съесть слово «И». Это не обязательно, и только приводит к другим проблемам.
Итак, что вам нужно сделать, так это настроить функцию, которая передает именованные совпадения для «величины» в функцию, которая просматривает все возможные значения величины и умножает ваш текущий результат на это значение величины. Затем вы создаете функцию, которая просматривает именованные совпадения «Value» и возвращает int (или что-то еще, что вы используете) на основе обнаруженного там значения.
Все совпадения VALUE ДОБАВЛЯЮТСЯ к вашему результату, в то время как совпадения Magnitutde умножают результат на значение mag. Таким образом, Двести пятьдесят тысяч становится «2», затем «2 * 100», затем «200 + 50», затем «250 * 1000», в итоге получается 250000. ..
Ради интереса я написал эту версию vbScript, и она отлично работала со всеми предоставленными примерами. Теперь он не поддерживает именованные совпадения, поэтому мне пришлось немного потрудиться, чтобы получить правильный результат, но я его получил. Суть в том, что если это совпадение «ЗНАЧЕНИЕ», добавьте его в свой аккумулятор. Если это совпадение величины, умножьте свой аккумулятор на 100, 1000, 1000000, 1000000000 и т. д. Это даст вам довольно удивительные результаты, и все, что вам нужно сделать, чтобы приспособиться к таким вещам, как «одна половина», это добавить их. к вашему регулярному выражению, поместите для них маркер кода и обработайте их.
Что ж, я надеюсь, что этот пост поможет КТО-НИБУДЬ. Если кто-то хочет, я могу опубликовать псевдокод vbScript, который я использовал для тестирования, однако это не красивый код, а НЕ производственный код.
Если позволите… На каком окончательном языке это будет написано? C++ или что-то вроде скриптового языка? Источник Грега Хьюгилла поможет понять, как все это объединяется.
Дайте мне знать, если я могу чем-то помочь. Извините, я знаю только английский/американский, поэтому не могу помочь вам с другими языками.
.net — Как преобразовать числа, написанные английскими словами, в их числовой эквивалент в F#?
Какой самый простой способ в F # (в функциональном/рекурсивном стиле) преобразовать число в словах в числовой эквивалент?
Пока смотрю только английский. Например:
let parseNumber (s : string) = сопоставить с | «Один» -> 1 | _ - отказ с "Не удается разобрать" пусть результат = parseNumber "одна тысяча двести" // результат должен быть 12000
Есть ли способ сделать это, не используя массивную справочную таблицу?
- .net
- рекурсия
- f#
- функциональное программирование
2
Вот наивное/простое решение, но вам потребуется расширить его для поддержки всех номеров (например, «Тридцать тысяч»):
open System пусть parseNumber (s: строка) = let parts = s.