Есть ли способ преобразовать числовые слова в целые числа?

Мне нужно преобразовать one в 1, two в 2 и так далее.

Есть ли способ сделать это с помощью библиотеки или класса или чего-то еще?


person Community    schedule 29.01.2009    source источник
comment
см. также: stackoverflow.com/questions/70161/   -  person tzot    schedule 30.01.2009
comment
Возможно, это будет полезно: pastebin.com/WwFCjYtt   -  person alvas    schedule 26.10.2015
comment
Если кто-то все еще ищет ответ на этот вопрос, я черпал вдохновение из всех приведенных ниже ответов и создал пакет python: github.com/careless25/text2digits   -  person stackErr    schedule 31.03.2019
comment
Я использовал приведенные ниже примеры для разработки и расширения этого процесса, но на испанский язык, для использования в будущем: github.com/elbaulp / text2digits_es   -  person ElBaulP    schedule 28.06.2019


Ответы (18)


Большая часть этого кода предназначена для настройки numwords dict, что выполняется только при первом вызове.

def text2int(textnum, numwords={}):
    if not numwords:
      units = [
        "zero", "one", "two", "three", "four", "five", "six", "seven", "eight",
        "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen",
        "sixteen", "seventeen", "eighteen", "nineteen",
      ]

      tens = ["", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"]

      scales = ["hundred", "thousand", "million", "billion", "trillion"]

      numwords["and"] = (1, 0)
      for idx, word in enumerate(units):    numwords[word] = (1, idx)
      for idx, word in enumerate(tens):     numwords[word] = (1, idx * 10)
      for idx, word in enumerate(scales):   numwords[word] = (10 ** (idx * 3 or 2), 0)

    current = result = 0
    for word in textnum.split():
        if word not in numwords:
          raise Exception("Illegal word: " + word)

        scale, increment = numwords[word]
        current = current * scale + increment
        if scale > 100:
            result += current
            current = 0

    return result + current

print text2int("seven billion one hundred million thirty one thousand three hundred thirty seven")
#7100031337
person recursive    schedule 29.01.2009
comment
К вашему сведению, это не сработает с датами. Попробуйте: print text2int("nineteen ninety six") # 115 - person Nick Ruiz; 13.05.2014
comment
Правильный способ записать число «1996» прописью - одна тысяча девятьсот девяносто шесть. Если вы хотите поддерживать годы, вам понадобится другой код. - person recursive; 13.05.2014
comment
Это делает рубиновый драгоценный камень Марка Бернса. Недавно я раздвоил его, чтобы добавить поддержку на долгие годы. Вы можете вызвать код ruby ​​из python. - person dimid; 05.03.2015
comment
Это ломается на «сто шесть» попыток. print (text2int (сто шесть)) .. также print (text2int (тысяча)) - person Harish Kayarohanam; 26.02.2017
comment
Правильный способ записи этих чисел - сто шесть и одна тысяча. Однако, если вам нужно разобраться с такими случаями, не стесняйтесь добавлять поддержку. - person recursive; 26.02.2017
comment
Важное замечание: это работает только для предложений в нижнем регистре. Убедитесь, что вы передаете предложение в нижнем регистре или работаете с переменной в нижнем регистре - person MikeL; 20.04.2017
comment
Это не работает для таких строк, как пять девять, что, как можно было бы ожидать, даст в результате 5 9. Вместо этого два числа объединяются. - person derekantrican; 23.10.2019
comment
чего и следовало ожидать. Полагаю, у разных пользователей разные ожидания. Лично я считаю, что он не будет вызываться с этим вводом, поскольку это неверный номер. Это два. - person recursive; 23.10.2019
comment
Фактически, это работает как для одной тысячи девятьсот девяноста шести, так и для девятисот девяноста шести. - person Stef; 02.12.2020

Я только что выпустил модуль python для PyPI под названием word2number именно для этой цели. https://github.com/akshaynagpal/w2n

Установите его, используя:

pip install word2number

убедитесь, что ваш pip обновлен до последней версии.

Использование:

from word2number import w2n

print w2n.word_to_num("two million three thousand nine hundred and eighty four")
2003984
person akshaynagpal    schedule 02.01.2016
comment
Пробовал ваш пакет. Предлагал бы обрабатывать такие строки, как: "1 million" или "1M". w2n.word_to_num (1 миллион) выдает ошибку. - person Ray; 04.05.2016
comment
@Ray Спасибо, что попробовали. Не могли бы вы поднять вопрос на странице github.com/akshaynagpal/w2n/issues. Вы также можете внести свой вклад, если хотите. В противном случае я обязательно рассмотрю этот вопрос в следующем выпуске. Еще раз спасибо! - person akshaynagpal; 04.05.2016
comment
Роберт, программное обеспечение с открытым исходным кодом - это все о людях, улучшающих его совместно. Мне нужна была библиотека, и я видел, что люди тоже хотят ее. Итак, сделал это. Возможно, он не готов для систем производственного уровня или не соответствует модным словечкам из учебников. Но это работает для цели. Кроме того, было бы здорово, если бы вы могли отправить PR, чтобы его можно было улучшить для всех пользователей. - person akshaynagpal; 07.08.2016
comment
он делает расчеты? Скажи: девятнадцать% пятьдесят семь? или любой другой оператор, то есть +, 6, * и / - person S.Jackson; 05.11.2020
comment
На данный момент это не так @ S.Jackson. - person akshaynagpal; 06.11.2020
comment
Я понимаю ! Я попробую разобраться в этом - person S.Jackson; 06.11.2020

Если кому-то интересно, я взломал версию, которая поддерживает остальную часть строки (хотя в ней могут быть ошибки, не тестировал слишком много).

def text2int (textnum, numwords={}):
    if not numwords:
        units = [
        "zero", "one", "two", "three", "four", "five", "six", "seven", "eight",
        "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen",
        "sixteen", "seventeen", "eighteen", "nineteen",
        ]

        tens = ["", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"]

        scales = ["hundred", "thousand", "million", "billion", "trillion"]

        numwords["and"] = (1, 0)
        for idx, word in enumerate(units):  numwords[word] = (1, idx)
        for idx, word in enumerate(tens):       numwords[word] = (1, idx * 10)
        for idx, word in enumerate(scales): numwords[word] = (10 ** (idx * 3 or 2), 0)

    ordinal_words = {'first':1, 'second':2, 'third':3, 'fifth':5, 'eighth':8, 'ninth':9, 'twelfth':12}
    ordinal_endings = [('ieth', 'y'), ('th', '')]

    textnum = textnum.replace('-', ' ')

    current = result = 0
    curstring = ""
    onnumber = False
    for word in textnum.split():
        if word in ordinal_words:
            scale, increment = (1, ordinal_words[word])
            current = current * scale + increment
            if scale > 100:
                result += current
                current = 0
            onnumber = True
        else:
            for ending, replacement in ordinal_endings:
                if word.endswith(ending):
                    word = "%s%s" % (word[:-len(ending)], replacement)

            if word not in numwords:
                if onnumber:
                    curstring += repr(result + current) + " "
                curstring += word + " "
                result = current = 0
                onnumber = False
            else:
                scale, increment = numwords[word]

                current = current * scale + increment
                if scale > 100:
                    result += current
                    current = 0
                onnumber = True

    if onnumber:
        curstring += repr(result + current)

    return curstring

Пример:

 >>> text2int("I want fifty five hot dogs for two hundred dollars.")
 I want 55 hot dogs for 200 dollars.

Могут возникнуть проблемы, если у вас есть, скажем, «200 долларов». Но это было действительно грубо.

person Andrew    schedule 04.08.2016
comment
Я взял этот и другие фрагменты кода отсюда и превратил их в библиотеку Python: github.com/careless25/text2digits - person stackErr; 31.03.2019

Мне нужно было что-то немного другое, поскольку мой ввод - это преобразование речи в текст, и решение не всегда состоит в суммировании чисел. Например, «мой почтовый индекс - один, два, три, четыре, пять» не следует преобразовывать в «мой почтовый индекс - 15».

Я взял ответ Эндрю и изменил его, чтобы обработать несколько других случаев, отмеченных как ошибки, а также добавил поддержку таких примеров, как почтовый индекс. Я уже упоминал выше. Ниже показаны некоторые базовые тестовые примеры, но я уверен, что еще есть возможности для улучшения.

def is_number(x):
    if type(x) == str:
        x = x.replace(',', '')
    try:
        float(x)
    except:
        return False
    return True

def text2int (textnum, numwords={}):
    units = [
        'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight',
        'nine', 'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen',
        'sixteen', 'seventeen', 'eighteen', 'nineteen',
    ]
    tens = ['', '', 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety']
    scales = ['hundred', 'thousand', 'million', 'billion', 'trillion']
    ordinal_words = {'first':1, 'second':2, 'third':3, 'fifth':5, 'eighth':8, 'ninth':9, 'twelfth':12}
    ordinal_endings = [('ieth', 'y'), ('th', '')]

    if not numwords:
        numwords['and'] = (1, 0)
        for idx, word in enumerate(units): numwords[word] = (1, idx)
        for idx, word in enumerate(tens): numwords[word] = (1, idx * 10)
        for idx, word in enumerate(scales): numwords[word] = (10 ** (idx * 3 or 2), 0)

    textnum = textnum.replace('-', ' ')

    current = result = 0
    curstring = ''
    onnumber = False
    lastunit = False
    lastscale = False

    def is_numword(x):
        if is_number(x):
            return True
        if word in numwords:
            return True
        return False

    def from_numword(x):
        if is_number(x):
            scale = 0
            increment = int(x.replace(',', ''))
            return scale, increment
        return numwords[x]

    for word in textnum.split():
        if word in ordinal_words:
            scale, increment = (1, ordinal_words[word])
            current = current * scale + increment
            if scale > 100:
                result += current
                current = 0
            onnumber = True
            lastunit = False
            lastscale = False
        else:
            for ending, replacement in ordinal_endings:
                if word.endswith(ending):
                    word = "%s%s" % (word[:-len(ending)], replacement)

            if (not is_numword(word)) or (word == 'and' and not lastscale):
                if onnumber:
                    # Flush the current number we are building
                    curstring += repr(result + current) + " "
                curstring += word + " "
                result = current = 0
                onnumber = False
                lastunit = False
                lastscale = False
            else:
                scale, increment = from_numword(word)
                onnumber = True

                if lastunit and (word not in scales):                                                                                                                                                                                                                                         
                    # Assume this is part of a string of individual numbers to                                                                                                                                                                                                                
                    # be flushed, such as a zipcode "one two three four five"                                                                                                                                                                                                                 
                    curstring += repr(result + current)                                                                                                                                                                                                                                       
                    result = current = 0                                                                                                                                                                                                                                                      

                if scale > 1:                                                                                                                                                                                                                                                                 
                    current = max(1, current)                                                                                                                                                                                                                                                 

                current = current * scale + increment                                                                                                                                                                                                                                         
                if scale > 100:                                                                                                                                                                                                                                                               
                    result += current                                                                                                                                                                                                                                                         
                    current = 0                                                                                                                                                                                                                                                               

                lastscale = False                                                                                                                                                                                                              
                lastunit = False                                                                                                                                                
                if word in scales:                                                                                                                                                                                                             
                    lastscale = True                                                                                                                                                                                                         
                elif word in units:                                                                                                                                                                                                             
                    lastunit = True

    if onnumber:
        curstring += repr(result + current)

    return curstring

Некоторые тесты ...

one two three -> 123
three forty five -> 345
three and forty five -> 3 and 45
three hundred and forty five -> 345
three hundred -> 300
twenty five hundred -> 2500
three thousand and six -> 3006
three thousand six -> 3006
nineteenth -> 19
twentieth -> 20
first -> 1
my zip is one two three four five -> my zip is 12345
nineteen ninety six -> 1996
fifty-seventh -> 57
one million -> 1000000
first hundred -> 100
I will buy the first thousand -> I will buy the 1000  # probably should leave ordinal in the string
thousand -> 1000
hundred and six -> 106
1 million -> 1000000
person totalhack    schedule 20.11.2018
comment
Я принял ваш ответ и исправил несколько ошибок. Добавлена ​​поддержка двадцати десятков - ›2010 и всех десятков в целом. Вы можете найти его здесь: github.com/careless25/text2digits - person stackErr; 31.03.2019
comment
Кажется, это работает лучше всего! Спасибо @totalhack - person user3480922; 02.01.2020
comment
он делает расчеты? Скажи: девятнадцать% пятьдесят семь? или любой другой оператор, то есть +, 6, * и / - person S.Jackson; 05.11.2020
comment
@ S.Jackson не делает расчетов. Если ваш текстовый фрагмент является действительным уравнением в Python, я полагаю, вы могли бы использовать его, чтобы сначала выполнить преобразование в целые числа, а затем eval результат (при условии, что вы знакомы и знакомы с проблемами безопасности, связанными с этим). Итак, десять + пять превращается в 10 + 5, тогда eval("10 + 5") дает вам 15. Однако это будет обрабатывать только самые простые случаи. Нет поплавков, скобок для управления порядком, поддержка озвучивания плюсов / минусов и т. Д. При преобразовании речи в текст. - person totalhack; 12.01.2021

Спасибо за фрагмент кода ... сэкономили мне много времени!

Мне нужно было обработать пару дополнительных случаев синтаксического анализа, таких как порядковые слова («первый», «второй»), слова с дефисом («сто») и порядковые слова с дефисом, такие как («пятьдесят седьмой»), поэтому я добавил пара строк:

def text2int(textnum, numwords={}):
    if not numwords:
        units = [
        "zero", "one", "two", "three", "four", "five", "six", "seven", "eight",
        "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen",
        "sixteen", "seventeen", "eighteen", "nineteen",
        ]

        tens = ["", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"]

        scales = ["hundred", "thousand", "million", "billion", "trillion"]

        numwords["and"] = (1, 0)
        for idx, word in enumerate(units):  numwords[word] = (1, idx)
        for idx, word in enumerate(tens):       numwords[word] = (1, idx * 10)
        for idx, word in enumerate(scales): numwords[word] = (10 ** (idx * 3 or 2), 0)

    ordinal_words = {'first':1, 'second':2, 'third':3, 'fifth':5, 'eighth':8, 'ninth':9, 'twelfth':12}
    ordinal_endings = [('ieth', 'y'), ('th', '')]

    textnum = textnum.replace('-', ' ')

    current = result = 0
    for word in textnum.split():
        if word in ordinal_words:
            scale, increment = (1, ordinal_words[word])
        else:
            for ending, replacement in ordinal_endings:
                if word.endswith(ending):
                    word = "%s%s" % (word[:-len(ending)], replacement)

            if word not in numwords:
                raise Exception("Illegal word: " + word)

            scale, increment = numwords[word]

         current = current * scale + increment
         if scale > 100:
            result += current
            current = 0

    return result + current`
person Jarret Hardie    schedule 28.02.2009
comment
Примечание: возвращает ноль для hundredth, thousandth и т. Д. Используйте one hundredth, чтобы получить 100! - person rohithpr; 26.03.2016

Это реализация кода в 1-м ответе на С #:

public static double ConvertTextToNumber(string text)
{
    string[] units = new string[] {
        "zero", "one", "two", "three", "four", "five", "six", "seven", "eight",
        "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen",
        "sixteen", "seventeen", "eighteen", "nineteen",
    };

    string[] tens = new string[] {"", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"};

    string[] scales = new string[] { "hundred", "thousand", "million", "billion", "trillion" };

    Dictionary<string, ScaleIncrementPair> numWord = new Dictionary<string, ScaleIncrementPair>();
    numWord.Add("and", new ScaleIncrementPair(1, 0));
    for (int i = 0; i < units.Length; i++)
    {
        numWord.Add(units[i], new ScaleIncrementPair(1, i));
    }

    for (int i = 1; i < tens.Length; i++)
    {
        numWord.Add(tens[i], new ScaleIncrementPair(1, i * 10));                
    }

    for (int i = 0; i < scales.Length; i++)
    {
        if(i == 0)
            numWord.Add(scales[i], new ScaleIncrementPair(100, 0));
        else
            numWord.Add(scales[i], new ScaleIncrementPair(Math.Pow(10, (i*3)), 0));
    }

    double current = 0;
    double result = 0;

    foreach (var word in text.Split(new char[] { ' ', '-', '—'}))
    {
        ScaleIncrementPair scaleIncrement = numWord[word];
        current = current * scaleIncrement.scale + scaleIncrement.increment;
        if (scaleIncrement.scale > 100)
        {
            result += current;
            current = 0;
        }
    }
    return result + current;
}


public struct ScaleIncrementPair
{
    public double scale;
    public int increment;
    public ScaleIncrementPair(double s, int i)
    {
        scale = s;
        increment = i;
    }
}
person e_h    schedule 23.04.2013
comment
Это то, что мне нравится - видеть расширения к ответам, которые расширяют различные способы реализации одного и того же ответа. Поскольку на вопрос уже был дан ответ, не помешало бы реализовать его на языке, который запрашивающий не указал. Но это действительно помогает людям, которые приходят попробовать реализовать код. За помощь будущим читателям этой проблемы +1 - person ; 30.08.2013

Вот тривиальный подход:

>>> number = {'one':1,
...           'two':2,
...           'three':3,}
>>> 
>>> number['two']
2

Или вы ищете что-то, что может выдержать "двенадцать тысяч сто семьдесят два"?

person Jeff Bauer    schedule 29.01.2009

Это можно легко закодировать в словарь, если есть ограниченное количество чисел, которые вы хотите проанализировать.

В более сложных случаях вы, вероятно, захотите сгенерировать этот словарь автоматически на основе относительно простой грамматики чисел. Что-то в этом роде (конечно, обобщенное ...)

for i in range(10):
   myDict[30 + i] = "thirty-" + singleDigitsDict[i]

Если вам нужно что-то более обширное, то, похоже, вам понадобятся инструменты обработки естественного языка. Эта статья может стать хорошей отправной точкой.

person Kena    schedule 29.01.2009

Быстрый и грязный порт Java для реализации e_h на C # (см. Выше). Обратите внимание, что оба возвращают double, а не int.

public class Text2Double {

    public double Text2Double(String text) {

        String[] units = new String[]{
                "zero", "one", "two", "three", "four", "five", "six", "seven", "eight",
                "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen",
                "sixteen", "seventeen", "eighteen", "nineteen",
        };

        String[] tens = new String[]{"", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"};

        String[] scales = new String[]{"hundred", "thousand", "million", "billion", "trillion"};

        Map<String, ScaleIncrementPair> numWord = new LinkedHashMap<>();
        numWord.put("and", new ScaleIncrementPair(1, 0));


        for (int i = 0; i < units.length; i++) {
            numWord.put(units[i], new ScaleIncrementPair(1, i));
        }

        for (int i = 1; i < tens.length; i++) {
            numWord.put(tens[i], new ScaleIncrementPair(1, i * 10));
        }

        for (int i = 0; i < scales.length; i++) {
            if (i == 0)
                numWord.put(scales[i], new ScaleIncrementPair(100, 0));
            else
                numWord.put(scales[i], new ScaleIncrementPair(Math.pow(10, (i * 3)), 0));
        }

        double current = 0;
        double result = 0;

        for(String word : text.split("[ -]"))
        {
            ScaleIncrementPair scaleIncrement = numWord.get(word);
            current = current * scaleIncrement.scale + scaleIncrement.increment;
            if (scaleIncrement.scale > 100) {
                result += current;
                current = 0;
            }
        }
        return result + current;
    }
}

public class ScaleIncrementPair
{
    public double scale;
    public int increment;

    public ScaleIncrementPair(double s, int i)
    {
        scale = s;
        increment = i;
    }
}
person user2029783    schedule 30.01.2017

Воспользуйтесь пакетом python: WordToDigits.

pip install wordtodigits

Он может находить числа, присутствующие в словесной форме в предложении, а затем преобразовывать их в правильный числовой формат. Также заботится о десятичной части, если она есть. Словесное представление чисел может быть в любом месте отрывка.

https://pypi.org/project/wordtodigits/

person Abhishek Rawat    schedule 30.05.2020

def parse_int(string):
ONES = {'zero': 0,
        '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,
          }
numbers = []
for token in string.replace('-', ' ').split(' '):
    if token in ONES:
        numbers.append(ONES[token])
    elif token == 'hundred':
        numbers[-1] *= 100
    elif token == 'thousand':
        numbers = [x * 1000 for x in numbers]
    elif token == 'million':
        numbers = [x * 1000000 for x in numbers]
return sum(numbers)

Я думаю, что этот код намного легче понять

протестировано с 700 случайными числами в диапазоне от 1 до миллиона работает хорошо

person hassan27sn    schedule 25.04.2021
comment
Я думаю, вам нужно уточнить свой вопрос, а как насчет вашего решения работает / не работает так, как задумано? - person khuynh; 26.04.2021
comment
Была исправлена ​​и протестирована ошибка. Спасибо за напоминание. - person hassan27sn; 27.04.2021

Внесены изменения, чтобы text2int (scale) возвращал правильное преобразование. Например, text2int ("сто") => 100.

import re

numwords = {}


def text2int(textnum):

    if not numwords:

        units = [ "zero", "one", "two", "three", "four", "five", "six",
                "seven", "eight", "nine", "ten", "eleven", "twelve",
                "thirteen", "fourteen", "fifteen", "sixteen", "seventeen",
                "eighteen", "nineteen"]

        tens = ["", "", "twenty", "thirty", "forty", "fifty", "sixty", 
                "seventy", "eighty", "ninety"]

        scales = ["hundred", "thousand", "million", "billion", "trillion", 
                'quadrillion', 'quintillion', 'sexillion', 'septillion', 
                'octillion', 'nonillion', 'decillion' ]

        numwords["and"] = (1, 0)
        for idx, word in enumerate(units): numwords[word] = (1, idx)
        for idx, word in enumerate(tens): numwords[word] = (1, idx * 10)
        for idx, word in enumerate(scales): numwords[word] = (10 ** (idx * 3 or 2), 0)

    ordinal_words = {'first':1, 'second':2, 'third':3, 'fifth':5, 
            'eighth':8, 'ninth':9, 'twelfth':12}
    ordinal_endings = [('ieth', 'y'), ('th', '')]
    current = result = 0
    tokens = re.split(r"[\s-]+", textnum)
    for word in tokens:
        if word in ordinal_words:
            scale, increment = (1, ordinal_words[word])
        else:
            for ending, replacement in ordinal_endings:
                if word.endswith(ending):
                    word = "%s%s" % (word[:-len(ending)], replacement)

            if word not in numwords:
                raise Exception("Illegal word: " + word)

            scale, increment = numwords[word]

        if scale > 1:
            current = max(1, current)

        current = current * scale + increment
        if scale > 100:
            result += current
            current = 0

    return result + current
person Dawa    schedule 21.04.2010
comment
Я думаю, что правильное английское написание 100 - это сотня. - person recursive; 28.04.2011
comment
@recursive, вы абсолютно правы, но преимущество этого кода в том, что он обрабатывает сотую часть (возможно, это то, что Дава пытался выделить). Судя по звуку описания, другому аналогичному коду требуется сотая часть, и это не всегда обычно используемый термин (например, как в случае, когда она выбрала сотый элемент, который нужно выбросить) - person Neil; 30.12.2016

Это делает рубиновый драгоценный камень Марка Бернса. Недавно я раздвоил его, чтобы добавить поддержку на долгие годы. Вы можете вызвать код ruby ​​из python.

  require 'numbers_in_words'
  require 'numbers_in_words/duck_punch'

  nums = ["fifteen sixteen", "eighty five sixteen",  "nineteen ninety six",
          "one hundred and seventy nine", "thirteen hundred", "nine thousand two hundred and ninety seven"]
  nums.each {|n| p n; p n.in_numbers}

результаты:
"fifteen sixteen" 1516 "eighty five sixteen" 8516 "nineteen ninety six" 1996 "one hundred and seventy nine" 179 "thirteen hundred" 1300 "nine thousand two hundred and ninety seven" 9297

person dimid    schedule 05.03.2015
comment
Пожалуйста, не вызывайте код Ruby из Python или код Python из Ruby. Они достаточно близки, чтобы что-то подобное можно было просто перенести. - person yekta; 10.10.2016
comment
Согласен, но пока он не портирован, вызывать рубиновый код лучше, чем ничего. - person dimid; 10.10.2016
comment
Это не очень сложно, ниже @recursive предоставил логику (с несколькими строками кода), которую можно использовать. - person yekta; 10.10.2016
comment
Мне на самом деле кажется, что пятнадцать шестнадцать - это неправильно? - person PascalVKooten; 29.10.2016
comment
@yekta Верно, я думаю, что рекурсивный ответ хорош в рамках ответа SO. Однако гем предоставляет полный пакет с тестами и другими функциями. Во всяком случае, я думаю, что у обоих есть свое место. - person dimid; 29.10.2016
comment
Существует пакет inflect python, который обрабатывает порядковые / количественные и числовые значения в слова. - person yekta; 31.10.2016
comment
@yekta, тогда вы должны предложить это в отдельном ответе. - person dimid; 31.10.2016

Быстрое решение - использовать inflect.py для создания словаря для перевода.

inflect.py имеет функцию number_to_words(), которая превращает число (например, 2) в его словоформу (например, 'two'). К сожалению, его обратный (который позволил бы избежать маршрута словаря перевода) не предлагается. Тем не менее, вы можете использовать эту функцию для создания словаря переводов:

>>> import inflect
>>> p = inflect.engine()
>>> word_to_number_mapping = {}
>>>
>>> for i in range(1, 100):
...     word_form = p.number_to_words(i)  # 1 -> 'one'
...     word_to_number_mapping[word_form] = i
...
>>> print word_to_number_mapping['one']
1
>>> print word_to_number_mapping['eleven']
11
>>> print word_to_number_mapping['forty-three']
43

Если вы готовы потратить какое-то время на фиксацию, возможно, можно будет изучить внутреннюю работу inflect.py функции number_to_words() и создать свой собственный код, чтобы делать это динамически (я не пробовал это делать).

person alukach    schedule 10.02.2014

Я взял логику @ recursive и преобразовал его в Ruby. Я также жестко запрограммировал таблицу поиска, так что это не так круто, но может помочь новичку понять, что происходит.

WORDNUMS = {"zero"=> [1,0], "one"=> [1,1], "two"=> [1,2], "three"=> [1,3],
            "four"=> [1,4], "five"=> [1,5], "six"=> [1,6], "seven"=> [1,7], 
            "eight"=> [1,8], "nine"=> [1,9], "ten"=> [1,10], 
            "eleven"=> [1,11], "twelve"=> [1,12], "thirteen"=> [1,13], 
            "fourteen"=> [1,14], "fifteen"=> [1,15], "sixteen"=> [1,16], 
            "seventeen"=> [1,17], "eighteen"=> [1,18], "nineteen"=> [1,19], 
            "twenty"=> [1,20], "thirty" => [1,30], "forty" => [1,40], 
            "fifty" => [1,50], "sixty" => [1,60], "seventy" => [1,70], 
            "eighty" => [1,80], "ninety" => [1,90],
            "hundred" => [100,0], "thousand" => [1000,0], 
            "million" => [1000000, 0]}

def texttwo thousand one hundred and forty-sixint(string)
  numberWords = string.gsub('-', ' ').split(/ /) - %w{and}
  current = result = 0
  numberWords.each do |word|
    scale, increment = WORDNUMS[word]
    current = current * scale + increment
    if scale > 100
      result += current
      current = 0
    end
  end
  return result + current
end

Я хотел обрабатывать такие строки, как two thousand one hundred and forty-six

person whatapalaver    schedule 22.07.2020

Этот код работает с данными серии:

import pandas as pd
mylist = pd.Series(['one','two','three'])
mylist1 = []
for x in range(len(mylist)):
    mylist1.append(w2n.word_to_num(mylist[x]))
print(mylist1)
person WireData india    schedule 03.08.2020

Это обрабатывает числа в словах индийского стиля, некоторые дроби, комбинации чисел и слов, а также сложение.

def words_to_number(words):
    numbers = {"zero":0, "a":1, "half":0.5, "quarter":0.25, "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}

    groups = {"hundred":100, "thousand":1_000, 
              "lac":1_00_000, "lakh":1_00_000, 
              "million":1_000_000, "crore":10**7, 
              "billion":10**9, "trillion":10**12}
    
    split_at = ["and", "plus"]
    
    n = 0
    skip = False
    words_array = words.split(" ")
    for i, word in enumerate(words_array):
        if not skip:
            if word in groups:
                n*= groups[word]
            elif word in numbers:
                n += numbers[word]
            elif word in split_at:
                skip = True
                remaining = ' '.join(words_array[i+1:])
                n+=words_to_number(remaining)
            else:
                try:
                    n += float(word)
                except ValueError as e:
                    raise ValueError(f"Invalid word {word}") from e
    return n

ТЕСТ:

print(words_to_number("a million and one"))
>> 1000001

print(words_to_number("one crore and one"))
>> 1000,0001

print(words_to_number("0.5 million one"))
>> 500001.0

print(words_to_number("half million and one hundred"))
>> 500100.0

print(words_to_number("quarter"))
>> 0.25

print(words_to_number("one hundred plus one"))
>> 101
person Hemant Hegde    schedule 27.06.2021
comment
Я сделал еще несколько тестов, семнадцать сотен = 1700 одна тысяча семьсот = 1700 НО одна тысяча семьсот = (одна тысяча семь) сотен = 1007 * 100 = 100700. Технически неправильно говорить тысяча семьсот вместо тысячи? И семьсот ?! - person Hemant Hegde; 27.06.2021

person    schedule
comment
пожалуйста, объясните, что делает этот код и как он это делает. Таким образом, ваш ответ будет более ценным для тех, кто еще не так хорошо разбирается в программировании. - person Luuklag; 21.08.2017
comment
Если пользователь указывает цифру в качестве ввода, программа вернет ее словами и наоборот, например, 5- ›пять, а для Five-› 5. программа работает для чисел ниже 100, но может быть расширена до любого диапазона, просто добавив несколько строк кода. - person Shriram Jadhav; 06.12.2017