Каков наиболее эффективный способ преобразования числовой суммы в английские слова
например. От 12 до двенадцати От 127 до ста двадцать семь
Каков наиболее эффективный способ преобразования числовой суммы в английские слова
например. От 12 до двенадцати От 127 до ста двадцать семь
Это не заняло много времени. Это реализация, написанная на 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");
}
}
В этой ссылке дается подробное объяснение того, что выглядит хорошим подходом: http://www.blackwasp.co.uk/NumberToWords.aspx
Один из способов добиться этого - использовать таблицы поиска. Это было бы немного грубой силой, но было бы легко настроить. Например, вы могли бы иметь слова для 0-99 в одной таблице, затем таблицу для десятков, сотен, тысяч и т.д. Простая математика даст вам индекс слова, который вам нужен из каждой таблицы.
Это старый код на моем жестком диске. Могут быть ошибки, но он должен показать основную идею:
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)]))
Это решение не пытается учитывать конечные пробелы, но это довольно быстро.
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;
}
Начните с решения 1-99, используя список чисел для 1-20, а затем 30, 40,..., 90. Затем добавьте сотни, чтобы получить 1-999. Затем используйте эту процедуру, чтобы дать количество каждой мощности 1000 на столько, сколько вы хотите (я думаю, что наивысшая стандартная номенклатура для дециллиона, что составляет 10 ^ 33).
Одно небольшое предостережение заключается в том, что немного сложно получить пробелы во всех случаях, если вы пытаетесь начать и завершить без лишнего пробела. Легкое решение состоит в том, чтобы поместить пробел после каждого слова, а затем вычеркнуть конечный бланк, когда вы все закончите. Если вы попытаетесь быть более точными при построении строки, вы, скорее всего, получите недостающие пробелы или лишние пробелы.
.) сделать библиотеку всех чисел и позиций (например, 1 имеет другую нотацию, чем 10, еще 100 и т.д.), .) составить список исключений (например, для 12) и знать, что в вашем алгоритме одно и то же исключение составляет 112, 1012 и т.д.
если вы хотите еще большую скорость, сделайте кешированный набор чисел, который вам нужен.
Обратите внимание на некоторые правила:
digit place
как "три тысячи".Вы можете получить место для номера, используя разделение полов целых чисел: 532/100 → 5
Это часть Common Lisp!
Здесь, как это делает GNU CLISP, и здесь, как CMUCL делает это (легче читать, ИМХО).
Выполнение поиска кода для "формата миллион миллиардов" станет большим количеством из них.