/* (C) 2007 Rafal Maj, LimCore.com Uses LC Num2Text software by LimCore www.limcore.com (on free LL GGC license). --- Free license: LL GGC (Gift, Give Credit) version 1 http://www.limcore.com/ll_ggc/1/ - simple license to promote & share code Gift "AS IS", use how you want, credit author while he wishes, include license. You are allowed to use this software (delivered "AS IS" - use at own risk!) in any way (including commercial use, closing source, creating derived work) if You always met this rules: Give credit, in any software (and in Your media describing that software, including WWW), where this (or derived) work is used, by showing in a visible way (in English and in main languages of derived work) text: "Uses TITLE software by NAME URL (on free LL GGC license).", replacing TITLE,NAME,URL with project title, author name and his website url, and providing access to copy of this license and all credits given by author. But remove credits if author requests it in writing. Also, name of author can not be used to endorse/promote derived work without author's permission; Above rules are inheritable - they apply as well to users of any fork or modification of this work - author of base/previous version (of this work) must be credited also. Happy using & coding --- TITLE for this source is: Num2Text NAME for this source is: LimCore URL for this source is: limcore.com --- Credits * Rafal Maj - author * Kaedenn - noticed 99*999 bug; translations? * Greetings to irc.freenode.org */ /* Version 1.1 Should spell (in words) numbers up to +- 999.999.999 that is up to nine hundred ninety-nine million nine hundred ninety-nine thousand nine hundred ninety-nine in * english * polish * add your language here =) and supports printing floats as euro (including eurocent). To support another language hack: copy SpellEn() -> SpellXx() and hack away SpellEuro() - just the euro printing change Print_String_As_Euro() and Teset() to debug new language */ #include #include #include #include #include #include #include #include #include using std::string; using std::map; using std::vector; using namespace boost::assign; // ===================================================================== template std::string STR(const T &val) { std::ostringstream str; str< w; w += "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten" , "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"; return w.at(num); } if (num<=99) { vector w; w += "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"; long ten = (num/10); long one = num%10; return w.at(ten-2) + ((one!=0) ? ("-"+SpellEn(one)) : ("")); } if (num<=999) { long hundred = num / 100; long rest = num % 100; return SpellEn(hundred) + " hundred" + ((rest!=0) ? (" "+SpellEn(rest)) : ("")); } if (num<=999999) { // hundreds of thousands long thousand = num / 1000; long rest = num % 1000; return SpellEn(thousand) + " thousand" + ((rest!=0) ? (" "+SpellEn(rest)) : ("")); } if (num<=999999999) { // hundreds of millions long million = num / 1000000; long rest = num % 1000000; return SpellEn(million) + " million" + ((rest!=0) ? (" "+SpellEn(rest)) : ("")); } return "???"; } // ===================================================================== string SpellPl(long num) { if (num<0) { return "minus " + SpellPl(-num); } if (num<=19) { vector w; w += "zero", "jeden", "dwa", "trzy", "cztery", "pięć", "sześć", "siedem", "osiem", "dziewięć", "dziesięć" , "jedenaście", "dwanaście", "trzynaście", "czternaście", "piętnaście", "szesnaście", "siedemnaście", "osiemnaście", "dziewiętnąscie"; return w.at(num); } if (num<=99) { vector w; w += "dwadzieścia", "trzydzieści", "czterdzieści", "pięćdziesiąt", "sześćdziesiąt", "siedemdziesiąt", "osiemdziesiąt", "dziewięćdziesiąt"; long ten = (num/10); long one = num%10; return w.at(ten-2) + ((one!=0) ? (" "+SpellPl(one)) : ("")); } if (num<=999) { long hundred = num / 100; string hundredStr="???"; { vector w; w += "???", "sto", "dwieście", "trzysta", "czterysta", "pięćset", "sześćset", "siedemset", "osiemset", "dziewięćset"; hundredStr = w.at(hundred); }; long rest = num % 100; return hundredStr + ((rest!=0) ? (" "+SpellPl(rest)) : ("")); } if (num<=999999) { // hundreds of thousands long thousand = num / 1000; string thousandStr=""; if (thousand==1) thousandStr = "tysiąc"; else if (thousand<=4) thousandStr = SpellPl(thousand) + " tysiące"; else thousandStr = SpellPl(thousand) + " tysięcy"; long rest = num % 1000; return thousandStr + ((rest!=0) ? (" "+SpellPl(rest)) : ("")); } if (num<=999999999) { // hundreds of millions long million = num / 1000000; string millionStr=""; if (million==1) millionStr = "milion"; else if (million<=4) millionStr = SpellPl(million) + " miliony"; else millionStr = SpellPl(million) + " milionów"; long rest = num % 1000000; return millionStr + ((rest!=0) ? (" "+SpellPl(rest)) : ("")); } return "???"; } // ===================================================================== void Test(long i) { std::cout << std::setw(5) << i << " is " << SpellEn(i) << std::endl; std::cout << std::setw(5) << i << " to " << SpellPl(i) << std::endl; } std::string SpellEuro(double num, const std::string & lang="en") { double numAbs = std::fabs(num); // absolute, so the minus can be handled by hand before the numbers long full = (long)numAbs; long cent = (long)(0.1 + (numAbs - full) * 100); // the minus part will be handled by full // (or will be added by hand, for -0.99 case where the "zero" is skipped) bool isZero = (full==0) && (cent==0); // 0.00 (after rouding if float num was strange) bool isMinus = num < 0; // std::cout << "\n[" << num << " -> " << numAbs << " gives e="<>num; cout << SpellEuro(num,"0.00") << " "; cout << SpellEuro(num,"0 00") << endl; cout << SpellEuro(num,"en") << " "; cout << SpellEuro(num,"pl") << endl; cout << endl; } // ===================================================================== // ===================================================================== // ===================================================================== void TestCase() { Test(-1); Test(0); Test(15); Test(1234); Test(18001); Test(3019); Test(-17934); Print_String_As_Euro("19352.94"); Print_String_As_Euro("2105.02"); Print_String_As_Euro("1444.01"); Print_String_As_Euro("99050"); Print_String_As_Euro("1.00"); Print_String_As_Euro("1.01"); Print_String_As_Euro("1.02"); Print_String_As_Euro("1.04"); Print_String_As_Euro("1.09"); Print_String_As_Euro("1.81"); Print_String_As_Euro("1.85"); Print_String_As_Euro("-0.99"); Print_String_As_Euro("-2.01"); Test(100); Test(10100); Test(1*100*1000); Test(2*100*1000); Test(9*100*1000); Test(9*100*1000 + 5003); Test(1000*1000); Test(2000*1000); Test(2000*1000 + 5007); Test(999111999); // 999 millions Print_String_As_Euro("-912000042.11"); // finall test \o/ Print_String_As_Euro("0"); Print_String_As_Euro("1"); Print_String_As_Euro("0.42"); Print_String_As_Euro("1.42"); Print_String_As_Euro("-0"); // yeah it doesnt make much sense, but just to test will it work like "0" Print_String_As_Euro("-1"); Print_String_As_Euro("-0.42"); Print_String_As_Euro("-1.42"); } void TestCaseFull() { // some test cases for (long i=-5; i<25; ++i) Test(i); for (long i=20; i<100; i+=10) { Test(i); Test(i+1); Test(i+9); } for (long i=100; i<1000; i+=100) { Test(i); Test(i+1); Test(i+11); Test(i+43); } for (long i=1000; i<20*1000; i+=1000) { Test(i); Test(i+1); Test(i+11); Test(i+43); Test(i+234); Test(i+354); Test(i+454); Test(i+654); Test(i+999); } TestCase(); } void ExecuteCommand(std::string command) { // command can be: // t - run test case // T - run full test case // 123.45 - a long number - spell it as Euro if (command=="T") TestCaseFull(); else if (command=="t") TestCase(); else Print_String_As_Euro(command); } int main(int argc, const char** argv) { using std::cout; using std::endl; std::string command; if (argc>=2) command = argv[1]; else { cout << "What to do?\n" " t - run testcase\n" " T - run full testcase\n" " 123.45 - or other number - spell it as euro value\n" "\nWrite and press ENTER\n"; std::cin >> command; } ExecuteCommand(command); }