Алгоритм, который преобразовывает числовую сумму в английские слова

Что самый эффективный путь состоит в том, чтобы преобразовать числовую сумму в английские слова

например, 12 к двенадцать 127 к сто двадцать семь

12
задан DuduAlul 21 July 2010 в 13:18
поделиться

9 ответов

Это не заняло много времени. Это реализация, написанная на Java.

http://snippets.dzone.com/posts/show/3685

Код

public class IntToEnglish {
    static String[] to_19 = { "zero",  "one",   "two",  "three", "four",   "five",   "six",
        "seven", "eight", "nine", "ten",   "eleven", "twelve", "thirteen",
        "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" };
    static String[] tens  = { "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"};
    static String[] denom = { "",
        "thousand",     "million",         "billion",       "trillion",       "quadrillion",
        "quintillion",  "sextillion",      "septillion",    "octillion",      "nonillion",
        "decillion",    "undecillion",     "duodecillion",  "tredecillion",   "quattuordecillion",
        "sexdecillion", "septendecillion", "octodecillion", "novemdecillion", "vigintillion" };

    public static void main(String[] argv) throws Exception {
        int tstValue = Integer.parseInt(argv[0]);
        IntToEnglish itoe = new IntToEnglish();
        System.out.println(itoe.english_number(tstValue));
        /* for (int i = 0; i < 2147483647; i++) {
            System.out.println(itoe.english_number(i));
        } */
    }
    // convert a value < 100 to English.
    private String convert_nn(int val) throws Exception {
        if (val < 20)
            return to_19[val];
        for (int v = 0; v < tens.length; v++) {
            String dcap = tens[v];
            int dval = 20 + 10 * v;
            if (dval + 10 > val) {
                if ((val % 10) != 0)
                    return dcap + "-" + to_19[val % 10];
                return dcap;
            }        
        }
        throw new Exception("Should never get here, less than 100 failure");
    }
    // convert a value < 1000 to english, special cased because it is the level that kicks 
    // off the < 100 special case.  The rest are more general.  This also allows you to
    // get strings in the form of "forty-five hundred" if called directly.
    private String convert_nnn(int val) throws Exception {
        String word = "";
        int rem = val / 100;
        int mod = val % 100;
        if (rem > 0) {
            word = to_19[rem] + " hundred";
            if (mod > 0) {
                word = word + " ";
            }
        }
        if (mod > 0) {
            word = word + convert_nn(mod);
        }
        return word;
    }
    public String english_number(int val) throws Exception {
        if (val < 100) {
            return convert_nn(val);
        }
        if (val < 1000) {
            return convert_nnn(val);
        }
        for (int v = 0; v < denom.length; v++) {
            int didx = v - 1;
            int dval = new Double(Math.pow(1000, v)).intValue();
            if (dval > val) {
                int mod = new Double(Math.pow(1000, didx)).intValue();
                int l = val / mod;
                int r = val - (l * mod);
                String ret = convert_nnn(l) + " " + denom[didx];
                if (r > 0) {
                    ret = ret + ", " + english_number(r);
                }
                return ret;
            }
        }
        throw new Exception("Should never get here, bottomed out in english_number");
    }
}
17
ответ дан 2 December 2019 в 04:52
поделиться

Эта ссылка предоставляет подробное объяснение того, что выглядит хорошим подходом: http://www.blackwasp.co.uk/NumberToWords.aspx

4
ответ дан 2 December 2019 в 04:52
поделиться

Один из способов добиться этого - использовать таблицы поиска. Это было бы грубой силой, но легко настроить. Например, у вас могут быть слова для 0-99 в одной таблице, а затем таблица для десятков, сотен, тысяч и т. Д. Некоторые простые математические вычисления дадут вам индекс нужного вам слова из каждой таблицы.

2
ответ дан 2 December 2019 в 04:52
поделиться

Это некоторый старый код python на моем жестком диске. Там могут быть ошибки, но он должен показать основную идею:

class Translator:
    def transformInt(self, x):
        translateNumbers(0,[str(x)])

    def threeDigitsNumber(self,number):
        snumber=self.twoDigitsNumber(number/100)
        if number/100!=0:
            snumber+=" hundred "
        snumber+self.twoDigitsNumber(number)
        return snumber+self.twoDigitsNumber(number)
    def twoDigitsNumber(self,number):
        snumber=""
        if number%100==10:
            snumber+="ten"
        elif number%100==11:
            snumber+="eleven"
        elif number%100==12:
            snumber+="twelve"
        elif number%100==13:
            snumber+="thirteen"
        elif number%100==14:
            snumber+="fourteen"
        elif number%100==15:
            snumber+="fifteen"
        elif number%100==16:
            snumber+="sixteen"
        elif number%100==17:
            snumber+="seventeen"
        elif number%100==18:
            snumber+="eighteen"
        elif number%100==19:
            snumber+="nineteen"
        else:
            if (number%100)/10==2:
                snumber+="twenty-"
            elif (number%100)/10==3:
                snumber+="thirty-"
            elif (number%100)/10==4:
                snumber+="forty-"
            elif (number%100)/10==5:
                snumber+="fifty-"
            elif (number%100)/10==6:
                snumber+="sixty-"
            elif (number%100)/10==7:
                snumber+="seventy-"
            elif (number%100)/10==8:
                snumber+="eighty-"
            elif (number%100)/10==9:
                snumber+="ninety-"
            if (number%10)==1:
                snumber+="one"
            elif (number%10)==2:
                snumber+="two"
            elif (number%10)==3:
                snumber+="three"
            elif (number%10)==4:
                snumber+="four"
            elif (number%10)==5:
                snumber+="five"
            elif (number%10)==6:
                snumber+="six"
            elif (number%10)==7:
                snumber+="seven"
            elif (number%10)==8:
                snumber+="eight"
            elif (number%10)==9:
                snumber+="nine"
            elif (number%10)==0:
                if snumber!="":
                    if snumber[len(snumber)-1]=="-":
                        snumber=snumber[0:len(snumber)-1]
        return snumber
    def translateNumbers(self,counter,words):
        if counter+1<len(words):
            self.translateNumbers(counter+1,words)
        else:
            if counter==len(words):
                return True
        k=0
        while k<len(words[counter]): 
            if (not (ord(words[counter][k])>47 and ord(words[counter][k])<58)):
                break
            k+=1
        if (k!=len(words[counter]) or k==0):
            return 1
        number=int(words[counter])
        from copy import copy
        if number==0:
            self.translateNumbers(counter+1,copy(words[0:counter]+["zero"]+words[counter+1:len(words)]))
            self.next.append(copy(words[0:counter]+["zero"]+words[counter+1:len(words)]))
            return 1
        if number<10000:
            self.translateNumbers(counter+1,copy(words[0:counter]
                                                      +self.seperatewords(self.threeDigitsNumber(number))
                                                      +words[counter+1:len(words)]))
            self.next.append(copy(words[0:counter]
                                       +self.seperatewords(self.threeDigitsNumber(number))
                                       +words[counter+1:len(words)]))
        if number>999:
            snumber=""
            if number>1000000000:
                snumber+=self.threeDigitsNumber(number/1000000000)+" billion "
                number=number%1000000000
            if number>1000000:
                snumber+=self.threeDigitsNumber(number/1000000)+" million "
                number=number%1000000
            if number>1000:
                snumber+=self.threeDigitsNumber(number/1000)+" thousand "
                number=number%1000
            snumber+=self.threeDigitsNumber(number)
            self.translateNumbers(counter+1,copy(words[0:counter]+self.seperatewords(snumber)
                                                      +words[counter+1:len(words)]))
            self.next.append(copy(words[0:counter]+self.seperatewords(snumber)
                                       +words[counter+1:len(words)]))
2
ответ дан 2 December 2019 в 04:52
поделиться

Это решение не пытается учесть конечные пробелы, но оно работает довольно быстро.

typedef const char* cstring;
using std::string;
using std::endl;
std::ostream& GetOnes(std::ostream &output, int onesValue)
{
    cstring ones[] = { "zero", "one", "two", "three", "four", "five", "six", 
           "seven", "eight", "nine" };
    output << ones[onesValue];
    return output;
}

std::ostream& GetSubMagnitude(std::ostream &output, int subMagnitude)
{
    cstring tens[] = { "zeroty", "ten", "twenty", "thirty", "fourty", "fifty", 
         "sixty", "seventy", "eighty", "ninety"};
    if (subMagnitude / 100 != 0)
    {       
        GetOnes(output, subMagnitude / 100) << " hundred ";
        GetSubMagnitude(output, subMagnitude - subMagnitude / 100 * 100);
    }
    else
    {
        if (subMagnitude >= 20)
        {
            output << tens[subMagnitude / 10] << " ";
            GetOnes(output, subMagnitude - subMagnitude / 10 * 10);
        }
        else if (subMagnitude >= 10)
        {
            cstring teens[] = { "ten", "eleven", "twelve", "thirteen",
                        "fourteen", "fifteen", "sixteen", "seventeen", 
                         "eighteen", "nineteen" };
            output << teens[subMagnitude - 10] << " ";
        }
        else 
        {
            GetOnes(output, subMagnitude) << " ";
        }
    }
    return output;
}

std::ostream& GetLongNumber(std::ostream &output, double input)
{
    cstring magnitudes[] = {"", "hundred", "thousand", "million", "billion", 
                           "trillion"};
    double magnitudeTests[] = {1, 100.0, 1000.0, 1000000.0, 1000000000.0, 
                           1000000000000.0 };
    int magTestIndex = 0;
    while (floor(input / magnitudeTests[magTestIndex++]) != 0);
    magTestIndex -= 2;
    if (magTestIndex >= 0) 
    {
        double subMagnitude = input / magnitudeTests[magTestIndex];
        GetSubMagnitude(output, (int)subMagnitude);
        if (magTestIndex) {
            output << magnitudes[magTestIndex] << " ";
            double remainder = input - (floor(input / 
                        magnitudeTests[magTestIndex]) * 
                        magnitudeTests[magTestIndex]);
            if (floor(remainder) > 0) 
            {
                GetLongNumber(output, remainder);
            }
        }
    }
    else
    {
        output << "zero";
    }
    return output;
}
2
ответ дан 2 December 2019 в 04:52
поделиться

Начните с решения 1-99, используя список чисел для 1-20, а затем 30, 40, ..., 90. Затем добавьте сотни, чтобы получить 1-999. Затем используйте эту подпрограмму, чтобы указать число каждой степени 1000 настолько высоко, насколько вы хотите (я думаю, что самая высокая стандартная номенклатура предназначена для дециллионов, что составляет 10 ^ 33).

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

2
ответ дан 2 December 2019 в 04:52
поделиться

.) Создайте библиотеку всех чисел и позиций (например, 1 имеет обозначение, отличное от 10, отличное от 100 и т. Д.) .) составьте список исключений (например, для 12) и имейте в виду, что в вашем алгоритме те же исключения предназначены для 112, 1012 и т. д.

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

1
ответ дан 2 December 2019 в 04:52
поделиться

Обратите внимание на некоторые правила:

  • Десятки (двадцать, тридцать и т.д.), оканчивающиеся на y, сопровождаются дефисами.
  • Подростки - особенные (кроме 15-19, но они все равно особенные).
  • Все остальное - это просто некоторая комбинация цифра-место, например "три тысячи".

Место числа можно узнать с помощью деления целых чисел на пол: 532 / 100 -> 5

1
ответ дан 2 December 2019 в 04:52
поделиться

Это часть Common Lisp!

Вот как это делает GNU CLISP, а вот как это делает CMUCL (легче читать, ИМХО).

Поиск по коду для "format million billion" выдаст множество таких запросов.

0
ответ дан 2 December 2019 в 04:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: