All pastes #838014 Raw Edit

Untitled

public text v1 · immutable
#838014 ·published 2007-12-30 01:28 UTC
rendered paste body
/*

(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 writting. 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 <iostream>
#include <sstream>
#include <map>
#include <vector>
#include <string>
#include <iomanip>
#include <cmath>
#include <boost/assign/std/vector.hpp>
#include <boost/assign/std/map.hpp>

using std::string;
using std::map;
using std::vector;
using namespace boost::assign;

// =====================================================================

template <typename T> std::string STR(const T &val) {
	std::ostringstream str;
	str<<val;
	return str.str();
}

// =====================================================================

/*
http://en.wikipedia.org/wiki/Euro
http://en.wikipedia.org/wiki/Cent_%28currency%29
http://en.wikipedia.org/wiki/Names_of_numbers_in_English
*/

string SpellEn(long num) {
	if (num<0) {
		return "minus " + SpellEn(-num);
	}

	if (num<=19) {
		vector<string> 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<string> 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<string> 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<string> 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<string> 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="<<full<<" c="<<cent<< "] \n";
	
	std::string out;

	if (lang=="0.00") {
		out += (isMinus?"-":"") + STR(full) + ".";
		if (cent<10) out += "0";
		out += STR(cent);
		out += "€";
	}
	else if (lang=="0 00") {
		out += "€" + STR(isMinus?"-":"") + STR(full) + " " + STR(cent) + "¢";
	}
	else if (lang=="en") {
		if (isMinus && !isZero) out += "minus "; // the !isZero shouldnt be needed probably but why not
		if (full || isZero) out += SpellEn(full) + " euro"; 
		if (cent!=0) { // cents
			if (full) out += " and "; // there was some full-euro part before
			out += SpellEn(cent) + " eurocent";
		}
	}
	else if (lang=="pl") {
		if (isMinus && !isZero) out += "minus "; // the !isZero shouldnt be needed probably but why not
		if (full || isZero) out += SpellPl(full) + " euro";
		if (cent!=0) { // cents
			if (full) out += " i "; // there was some full-euro part before

			// damn polish grammer:
			//
			//  rule1:  0.. 9 is: 1-grosz   2..4-grosze  5..9-groszy
			//  rule2: 10..19 is: 11..19-groszy
			//  rule3: 20..99 is: n0-groszy  n1-groszy  n2..n4-grosze  n5..n9-groszy  where n is 20,30,40..90
			//  s/grosz/eurocent
			//  s/grosze/eurocenty
			//  s/groszy/eurocentów
			//  sigh :)

			out += SpellPl(cent) + " ";
			if (cent<=9) { // rule1
				if (cent==1) out+="eurocent"; // 1
				else if (cent<=4) out+="eurocenty"; // 2 3 4
				else out+="eurocentów"; // 8
			}
			else if (cent<=19) { // rule 2
				out+="eurocentów"; // 12
			}
			else { // rule3
				long d = cent % 10;
				if (d==0) out += "eurocentów"; // 20 30 40
				else if (d==1) out += "eurocentów"; // 21 31 91
				else if (d<=4) out += "eurocenty"; // 22 23 24 54 75
				else out += "eurocentów"; // 25 55 75 99
			}
		}
	}

	return out;
}

void Print_String_As_Euro(std::string str) {
	using std::cout; using std::endl;
		
	double num=0;
	std::istringstream istr(str);
	istr>>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);

}