Что ж, я опоздал с ответом на этот вопрос, но я работал над небольшим тестовым сценарием, который, похоже, мне очень помог. Я использовал (простое, но безобразное и большое) регулярное выражение, чтобы найти все слова для меня. Выражение выглядит следующим образом:
(?<Value>(?:zero)|(?:one|first)|(?:two|second)|(?:three|third)|(?:four|fourth)|
(?:five|fifth)|(?:six|sixth)|(?:seven|seventh)|(?:eight|eighth)|(?:nine|ninth)|
(?:ten|tenth)|(?:eleven|eleventh)|(?:twelve|twelfth)|(?:thirteen|thirteenth)|
(?:fourteen|fourteenth)|(?:fifteen|fifteenth)|(?:sixteen|sixteenth)|
(?:seventeen|seventeenth)|(?:eighteen|eighteenth)|(?:nineteen|nineteenth)|
(?:twenty|twentieth)|(?:thirty|thirtieth)|(?:forty|fortieth)|(?:fifty|fiftieth)|
(?:sixty|sixtieth)|(?:seventy|seventieth)|(?:eighty|eightieth)|(?:ninety|ninetieth)|
(?<Magnitude>(?:hundred|hundredth)|(?:thousand|thousandth)|(?:million|millionth)|
(?:billion|billionth)))
Здесь показано с разрывами строк для форматирования.
В любом случае, мой метод состоял в том, чтобы выполнить это RegEx с библиотекой, подобной PCRE, и затем прочитать названные совпадения. И он работал на всех различных примерах, перечисленных в этом вопросе, за исключением типов «Одна половина», поскольку я их не добавил, но, как вы можете видеть, это не составит труда сделать. Это решает много вопросов. Например, он касается следующих пунктов исходного вопроса и других ответов:
- Кардинал / номинал или порядковый номер: «один» и «первый»
- Распространенные орфографические ошибки: «сорок» / «Сорок» (обратите внимание, что это НЕ ТОЧНО решает эту проблему, это было бы то, что вы хотели бы сделать, прежде чем передать строку этому анализатору. Этот анализатор видит этот пример как « ЧЕТВЕРТЫЙ»...)
- сотни / тысячи: 2100 -> «двадцать одна сотня», а также «две тысячи сто»
- разделители: "одиннадцатьсот пятьдесят два", но также "одиннадцатьсот пятьдесят два" или "одиннадцатьсот пятьдесят два" и еще много чего
- коллоквиализмы: «тридцать с чем-то» (это также не ПОЛНОСТЬЮ решено, как то, что «что-то»? Ну, этот код находит это число как просто «30»). **
Теперь, вместо того, чтобы хранить этого монстра регулярного выражения в вашем источнике, я подумывал о создании этого RegEx во время выполнения, используя что-то вроде следующего:
char *ones[] = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve",
"thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"};
char *tens[] = {"", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"};
char *ordinalones[] = { "", "first", "second", "third", "fourth", "fifth", "", "", "", "", "", "", "twelfth" };
char *ordinaltens[] = { "", "", "twentieth", "thirtieth", "fortieth", "fiftieth", "sixtieth", "seventieth", "eightieth", "ninetieth" };
and so on...
Легкая часть здесь - мы храним только те слова, которые имеют значение. В случае ШЕСТОГО вы заметите, что для него нет записи, потому что это просто обычный номер с прикрепленным TH ... Но такие, как TWELVE, требуют другого внимания.
Хорошо, теперь у нас есть код для построения нашего (безобразного) RegEx, теперь мы просто выполняем его на наших числовых строках.
Одна вещь, которую я бы порекомендовал, это фильтровать или есть слово «И». Это не обязательно, и только приводит к другим проблемам.
Итак, вам нужно настроить функцию, которая передает именованные совпадения для «Величины» в функцию, которая просматривает все возможные значения величины и умножает ваш текущий результат на это значение величины. Затем вы создаете функцию, которая просматривает именованные совпадения «Value» и возвращает int (или то, что вы используете) на основе обнаруженного там значения.
Все совпадения VALUE ДОБАВЛЯЮТСЯ в ваш результат, а совпадения Magnitutde умножают результат на значение mag. Таким образом, двести пятьдесят тысяч становится «2», затем «2 * 100», затем «200 + 50», затем «250 * 1000», заканчивая 250000 ...
Просто для забавы я написал эту версию на vbScript, и она прекрасно работала со всеми представленными примерами. Теперь он не поддерживает именованные совпадения, поэтому мне пришлось потрудиться, чтобы получить правильный результат, но я его получил. Суть в том, что если это совпадение VALUE, добавьте его в свой аккумулятор. Если это совпадение по величине, умножьте свой аккумулятор на 100, 1000, 1000000, 1000000000 и т. Д. ... Это даст вам довольно удивительные результаты, и все, что вам нужно сделать, чтобы приспособиться к таким вещам, как "половина", это добавить их в свой RegEx, введите для них маркер кода и обработайте их.
Ну, я надеюсь, что этот пост поможет кому-то там. Если кто-то захочет, я могу опубликовать псевдокод vbScript, который я использовал для проверки этого, однако это не красивый код, а НЕ производственный код.
Если позволите ... На каком языке это будет написано? C ++ или что-то вроде скриптового языка? Источник Грега Хьюгилла поможет понять, как все это происходит вместе.
Дайте мне знать, могу ли я чем-нибудь помочь. Извините, я знаю только английский / американский, поэтому не могу помочь вам с другими языками.