Added setup.py and restructured module

This commit is contained in:
Marius Grigaitis
2011-06-07 17:28:19 +03:00
parent 46f1f84bdc
commit 8f122281c2
13 changed files with 10 additions and 0 deletions

60
pynum2word/num2word.py Normal file
View File

@@ -0,0 +1,60 @@
'''
Module: num2word.py
Requires: num2word_*.py
Version: 0.2
Author:
Taro Ogawa (tso@users.sourceforge.org)
Copyright:
Copyright (c) 2003, Taro Ogawa. All Rights Reserved.
Licence:
This module is distributed under the Lesser General Public Licence.
http://www.opensource.org/licenses/lgpl-license.php
Usage:
from num2word import to_card, to_ord, to_ordnum
to_card(1234567890)
to_ord(1234567890)
to_ordnum(12)
Notes:
The module is a wrapper for language-specific modules. It imports the
appropriate modules as defined by locale settings. If unable to
load an appropriate module, an ImportError is raised.
History:
0.2: n2w, to_card, to_ord, to_ordnum now imported correctly
'''
import locale as _locale
# Correct omissions in locale:
# Bugrep these...
_locdict = { "English_Australia" : "en_AU", }
_modules = []
for _loc in [_locale.getlocale(), _locale.getdefaultlocale()]:
_lang = _loc[0]
if _lang:
_lang = _locdict.get(_lang, _lang)
_lang = _lang.upper()
_modules.append("num2word_" + _lang)
_modules.append("num2word_" + _lang.split("_")[0])
for _module in _modules:
try:
n2wmod = __import__(_module)
break
except ImportError:
pass
try:
n2w, to_card, to_ord, to_ordnum, to_year = (n2wmod.n2w, n2wmod.to_card,
n2wmod.to_ord, n2wmod.to_ordnum,
n2wmod.to_year)
except NameError:
raise ImportError("Could not import any of these modules: %s"
% (", ".join(_modules)))

154
pynum2word/num2word_DE.py Normal file
View File

@@ -0,0 +1,154 @@
'''
Module: num2word_DE.py
Requires: num2word_base.py
Version: 0.4
Author:
Taro Ogawa (tso@users.sourceforge.org)
Copyright:
Copyright (c) 2003, Taro Ogawa. All Rights Reserved.
Licence:
This module is distributed under the Lesser General Public Licence.
http://www.opensource.org/licenses/lgpl-license.php
Data from:
- http://german4u2know.tripod.com/nouns/10.html
- http://www.uni-bonn.de/~manfear/large.php
Usage:
from num2word_DE import to_card, to_ord, to_ordnum
to_card(1234567890)
to_ord(1234567890)
to_ordnum(12)
History
0.4: Use high ascii characters instead of low ascii approximations
add to_currency() and to_year()
'''
from num2word_EU import Num2Word_EU
#//TODO: Use German error messages
class Num2Word_DE(Num2Word_EU):
def set_high_numwords(self, high):
max = 3 + 6*len(high)
for word, n in zip(high, range(max, 3, -6)):
self.cards[10**n] = word + "illiarde"
self.cards[10**(n-3)] = word + "illion"
def setup(self):
self.negword = "minus "
self.pointword = "Komma"
self.errmsg_nonnum = "Only numbers may be converted to words."
self.errmsg_toobig = "Number is too large to convert to words."
self.exclude_title = []
lows = ["non", "okt", "sept", "sext", "quint", "quadr", "tr", "b", "m"]
units = ["", "un", "duo", "tre", "quattuor", "quin", "sex", "sept",
"okto", "novem"]
tens = ["dez", "vigint", "trigint", "quadragint", "quinquagint",
"sexagint", "septuagint", "oktogint", "nonagint"]
self.high_numwords = ["zent"]+self.gen_high_numwords(units, tens, lows)
self.mid_numwords = [(1000, "tausand"), (100, "hundert"),
(90, "neunzig"), (80, "achtzig"), (70, "siebzig"),
(60, "sechzig"), (50, "f\xFCnfzig"), (40, "vierzig"),
(30, "drei\xDFig")]
self.low_numwords = ["zwanzig", "neunzehn", "achtzen", "siebzehn",
"sechzehn", "f\xFCnfzehn", "vierzehn", "dreizehn",
"zw\xF6lf", "elf", "zehn", "neun", "acht", "sieben",
"sechs", "f\xFCnf", "vier", "drei", "zwei", "eins",
"null"]
self.ords = { "eins" : "ers",
"drei" : "drit",
"acht" : "ach",
"sieben" : "sieb",
"ig" : "igs" }
self.ordflag = False
def merge(self, curr, next):
ctext, cnum, ntext, nnum = curr + next
if cnum == 1:
if nnum < 10**6 or self.ordflag:
return next
ctext = "eine"
if nnum > cnum:
if nnum >= 10**6:
if cnum > 1:
if ntext.endswith("e") or self.ordflag:
ntext += "s"
else:
ntext += "es"
ctext += " "
val = cnum * nnum
else:
if nnum < 10 < cnum < 100:
if nnum == 1:
ntext = "ein"
ntext, ctext = ctext, ntext + "und"
elif cnum >= 10**6:
ctext += " "
val = cnum + nnum
word = ctext + ntext
return (word, val)
def to_ordinal(self, value):
self.verify_ordinal(value)
self.ordflag = True
outword = self.to_cardinal(value)
self.ordflag = False
for key in self.ords:
if outword.endswith(key):
outword = outword[:len(outword) - len(key)] + self.ords[key]
break
return outword + "te"
# Is this correct??
def to_ordinal_num(self, value):
self.verify_ordinal(value)
return str(value) + "te"
def to_currency(self, val, longval=True, old=False):
if old:
return self.to_splitnum(val, hightxt="mark/s", lowtxt="pfennig/e",
jointxt="und",longval=longval)
return super(Num2Word_DE, self).to_currency(val, jointxt="und",
longval=longval)
def to_year(self, val, longval=True):
if not (val//100)%10:
return self.to_cardinal(val)
return self.to_splitnum(val, hightxt="hundert", longval=longval)
n2w = Num2Word_DE()
to_card = n2w.to_cardinal
to_ord = n2w.to_ordinal
to_ordnum = n2w.to_ordinal_num
def main():
for val in [ 1, 11, 12, 21, 31, 33, 71, 80, 81, 91, 99, 100, 101, 102, 155,
180, 300, 308, 832, 1000, 1001, 1061, 1100, 1500, 1701, 3000,
8280, 8291, 150000, 500000, 1000000, 2000000, 2000001,
-21212121211221211111, -2.121212, -1.0000100]:
n2w.test(val)
n2w.test(1325325436067876801768700107601001012212132143210473207540327057320957032975032975093275093275093270957329057320975093272950730)
print n2w.to_currency(112121)
print n2w.to_year(2000)
if __name__ == "__main__":
main()

135
pynum2word/num2word_EN.py Normal file
View File

@@ -0,0 +1,135 @@
'''
Module: num2word_EN.py
Requires: num2word_EU.py
Version: 1.2
Author:
Taro Ogawa (tso@users.sourceforge.org)
Copyright:
Copyright (c) 2003, Taro Ogawa. All Rights Reserved.
Licence:
This module is distributed under the Lesser General Public Licence.
http://www.opensource.org/licenses/lgpl-license.php
Data from:
http://www.uni-bonn.de/~manfear/large.php
Usage:
from num2word_EN import n2w, to_card, to_ord, to_ordnum
to_card(1234567890)
n2w.is_title = True
to_card(1234567890)
to_ord(1234567890)
to_ordnum(1234567890)
to_year(1976)
to_currency(dollars*100 + cents, longval=False)
to_currency((dollars, cents))
History:
1.2: to_ordinal_num() made shorter and simpler (but slower)
strings in merge() now interpolated
to_year() and to_currency() added
1.1: to_ordinal_num() fixed for 11,12,13
'''
from __future__ import division
import num2word_EU
class Num2Word_EN(num2word_EU.Num2Word_EU):
def set_high_numwords(self, high):
max = 3 + 3*len(high)
for word, n in zip(high, range(max, 3, -3)):
self.cards[10**n] = word + "illion"
def setup(self):
self.negword = "minus "
self.pointword = "point"
self.errmsg_nornum = "Only numbers may be converted to words."
self.exclude_title = ["and", "point", "minus"]
self.mid_numwords = [(1000, "thousand"), (100, "hundred"),
(90, "ninety"), (80, "eighty"), (70, "seventy"),
(60, "sixty"), (50, "fifty"), (40, "forty"),
(30, "thirty")]
self.low_numwords = ["twenty", "nineteen", "eighteen", "seventeen",
"sixteen", "fifteen", "fourteen", "thirteen",
"twelve", "eleven", "ten", "nine", "eight",
"seven", "six", "five", "four", "three", "two",
"one", "zero"]
self.ords = { "one" : "first",
"two" : "second",
"three" : "third",
"five" : "fifth",
"eight" : "eighth",
"nine" : "ninth",
"twelve" : "twelfth" }
def merge(self, (ltext, lnum), (rtext, rnum)):
if lnum == 1 and rnum < 100:
return (rtext, rnum + lnum)
elif 100 > lnum > rnum :
return ("%s-%s"%(ltext, rtext), lnum + rnum)
elif lnum >= 100 > rnum:
return ("%s and %s"%(ltext, rtext), lnum + rnum)
elif rnum > lnum:
return ("%s %s"%(ltext, rtext), lnum * rnum)
return ("%s, %s"%(ltext, rtext), lnum + rnum)
def to_ordinal(self, value):
self.verify_ordinal(value)
outwords = self.to_cardinal(value).split(" ")
lastwords = outwords[-1].split("-")
lastword = lastwords[-1].lower()
try:
lastword = self.ords[lastword]
except KeyError:
if lastword[-1] == "y":
lastword = lastword[:-1] + "ie"
lastword += "th"
lastwords[-1] = self.title(lastword)
outwords[-1] = "-".join(lastwords)
return " ".join(outwords)
def to_ordinal_num(self, value):
self.verify_ordinal(value)
return "%s%s"%(value, self.to_ordinal(value)[-2:])
def to_year(self, val, longval=True):
if not (val//100)%10:
return self.to_cardinal(val)
return self.to_splitnum(val, hightxt="hundred", jointxt="and",
longval=longval)
def to_currency(self, val, longval=True):
return self.to_splitnum(val, hightxt="dollar/s", lowtxt="cent/s",
jointxt="and", longval=longval)
n2w = Num2Word_EN()
to_card = n2w.to_cardinal
to_ord = n2w.to_ordinal
to_ordnum = n2w.to_ordinal_num
to_year = n2w.to_year
def main():
for val in [ 1, 11, 12, 21, 31, 33, 71, 80, 81, 91, 99, 100, 101, 102, 155,
180, 300, 308, 832, 1000, 1001, 1061, 1100, 1500, 1701, 3000,
8280, 8291, 150000, 500000, 1000000, 2000000, 2000001,
-21212121211221211111, -2.121212, -1.0000100]:
n2w.test(val)
n2w.test(1325325436067876801768700107601001012212132143210473207540327057320957032975032975093275093275093270957329057320975093272950730)
for val in [1,120,1000,1120,1800, 1976,2000,2010,2099,2171]:
print val, "is", n2w.to_currency(val)
print val, "is", n2w.to_year(val)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,62 @@
'''
Module: num2word_EN_EUR.py
Requires: num2word_EN.py
Version: 1.0
Author:
Taro Ogawa (tso@users.sourceforge.org)
Copyright:
Copyright (c) 2003, Taro Ogawa. All Rights Reserved.
Licence:
This module is distributed under the Lesser General Public Licence.
http://www.opensource.org/licenses/lgpl-license.php
Data from:
http://www.uni-bonn.de/~manfear/large.php
Usage:
from num2word_EN import n2w, to_card, to_ord, to_ordnum
to_card(1234567890)
n2w.is_title = True
to_card(1234567890)
to_ord(1234567890)
to_ordnum(1234567890)
to_year(1976)
to_currency(euros*100 + cents)
to_currency((euros,cents))
'''
from num2word_EN import Num2Word_EN
class Num2Word_EN_EUR(Num2Word_EN):
def to_currency(self, val, longval=True):
return self.to_splitnum(val, hightxt="euro/s", lowtxt="cents",
jointxt="and", longval=longval)
n2w = Num2Word_EN_EUR()
to_card = n2w.to_cardinal
to_ord = n2w.to_ordinal
to_ordnum = n2w.to_ordinal_num
to_year = n2w.to_year
to_currency = n2w.to_currency
def main():
for val in [ 1, 11, 12, 21, 31, 33, 71, 80, 81, 91, 99, 100, 101, 102, 155,
180, 300, 308, 832, 1000, 1001, 1061, 1100, 1500, 1701, 3000,
8280, 8291, 150000, 500000, 1000000, 2000000, 2000001,
-21212121211221211111, -2.121212, -1.0000100]:
n2w.test(val)
n2w.test(1325325436067876801768700107601001012212132143210473207540327057320957032975032975093275093275093270957329057320975093272950730)
for val in [1,120,1000,1120,1800, 1976,2000,2010,2099,2171]:
print val, "is", n2w.to_currency(val)
print val, "is", n2w.to_year(val)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,63 @@
'''
Module: num2word_EN_GB.py
Requires: num2word_EN.py
Version: 1.0
Author:
Taro Ogawa (tso@users.sourceforge.org)
Copyright:
Copyright (c) 2003, Taro Ogawa. All Rights Reserved.
Licence:
This module is distributed under the Lesser General Public Licence.
http://www.opensource.org/licenses/lgpl-license.php
Data from:
http://www.uni-bonn.de/~manfear/large.php
Usage:
from num2word_EN import n2w, to_card, to_ord, to_ordnum
to_card(1234567890)
n2w.is_title = True
to_card(1234567890)
to_ord(1234567890)
to_ordnum(1234567890)
to_year(1976)
to_currency(pounds*100 + pence)
to_currency((pounds,pence))
History:
1.0: Split from num2word_EN with the addition of to_currency()
'''
from num2word_EN import Num2Word_EN
class Num2Word_EN_GB(Num2Word_EN):
def to_currency(self, val, longval=True):
return self.to_splitnum(val, hightxt="pound/s", lowtxt="pence",
jointxt="and", longval=longval)
n2w = Num2Word_EN_GB()
to_card = n2w.to_cardinal
to_ord = n2w.to_ordinal
to_ordnum = n2w.to_ordinal_num
to_year = n2w.to_year
def main():
for val in [ 1, 11, 12, 21, 31, 33, 71, 80, 81, 91, 99, 100, 101, 102, 155,
180, 300, 308, 832, 1000, 1001, 1061, 1100, 1500, 1701, 3000,
8280, 8291, 150000, 500000, 1000000, 2000000, 2000001,
-21212121211221211111, -2.121212, -1.0000100]:
n2w.test(val)
n2w.test(1325325436067876801768700107601001012212132143210473207540327057320957032975032975093275093275093270957329057320975093272950730)
for val in [1,120,1000,1120,1800, 1976,2000,2010,2099,2171]:
print val, "is", n2w.to_currency(val)
print val, "is", n2w.to_year(val)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,55 @@
'''
Module: num2word_EN_GB_old.py
Requires: num2word_EN_GB_old.py
Version: 0.3
Author:
Taro Ogawa (tso@users.sourceforge.org)
Copyright:
Copyright (c) 2003, Taro Ogawa. All Rights Reserved.
Licence:
This module is distributed under the Lesser General Public Licence.
http://www.opensource.org/licenses/lgpl-license.php
Usage:
from num2word_EN_old import to_card, to_ord, to_ordnum
to_card(1234567890)
to_ord(1234567890)
to_ordnum(12)
History:
0.3: Rename from num2word_EN_old
Todo:
Currency (pounds/shillings/pence)
'''
from num2word_EN_GB import Num2Word_EN_GB
class Num2Word_EN_GB_old(Num2Word_EN_GB):
def base_setup(self):
sclass = super(Num2Word_EN_GB, self)
self.set_high_numwords = sclass.set_high_numwords
sclass.base_setup()
n2w = Num2Word_EN_GB_old()
to_card = n2w.to_cardinal
to_ord = n2w.to_ordinal
to_ordnum = n2w.to_ordinal_num
def main():
for val in [ 1, 11, 12, 21, 31, 33, 71, 80, 81, 91, 99, 100, 101, 102, 155,
180, 300, 308, 832, 1000, 1001, 1061, 1100, 1500, 1701, 3000,
8280, 8291, 150000, 500000, 1000000, 2000000, 2000001,
-21212121211221211111, -2.121212, -1.0000100]:
n2w.test(val)
n2w.test(1325325436067876801768700107601001012212132143210473207540327057320957032975032975093275093275093270957329057320975093272950730)
for val in [1,120,1000,1120,1800, 1976,2000,2010,2099,2171]:
print val, "is", n2w.to_currency(val)
print val, "is", n2w.to_year(val)
if __name__ == "__main__":
main()

147
pynum2word/num2word_ES.py Normal file
View File

@@ -0,0 +1,147 @@
'''
Module: num2word_ES.py
Requires: num2word_EU.py
Version: 0.3
Author:
Taro Ogawa (tso@users.sourceforge.org)
Copyright:
Copyright (c) 2003, Taro Ogawa. All Rights Reserved.
Licence:
This module is distributed under the Lesser General Public Licence.
http://www.opensource.org/licenses/lgpl-license.php
Data from:
http://www.smartphrase.com/Spanish/sp_numbers_voc.shtml
Usage:
from num2word_ES import to_card, to_ord, to_ordnum
to_card(1234567890)
to_ord(1234567890)
to_ordnum(12)
History:
0.3: Use high ascii characters instead of low ascii approximations
String interpolation where it makes things clearer
add to_currency()
'''
from num2word_EU import Num2Word_EU
#//TODO: correct orthographics
#//TODO: error messages
class Num2Word_ES(Num2Word_EU):
#//CHECK: Is this sufficient??
def set_high_numwords(self, high):
max = 3 + 6*len(high)
for word, n in zip(high, range(max, 3, -6)):
self.cards[10**(n-3)] = word + "ill\xf2n"
def setup(self):
lows = ["cuatr", "tr", "b", "m"]
self.high_numwords = self.gen_high_numwords([], [], lows)
self.negword = "menos "
self.pointword = "punto"
self.errmsg_nonnum = "Only numbers may be converted to words."
self.errmsg_toobig = "Number is too large to convert to words."
self.gender_stem = "o"
self.exclude_title = ["y", "menos", "punto"]
self.mid_numwords = [(1000, "mil"), (100, "cien"), (90, "noventa"),
(80, "ochenta"), (70, "setenta"), (60, "sesenta"),
(50,"cincuenta"), (40,"cuarenta")]
self.low_numwords = ["vientinueve", "vientiocho", "vientisiete",
"vientis\xE8is", "vienticinco", "vienticuatro",
"vientitr\xE8s", "vientid\xF2s", "vientiuno",
"viente", "diecinueve", "dieciocho", "diecisiete",
"dieciseis", "quince", "catorce", "trece", "doce",
"once", "diez", "nueve", "ocho", "siete", "seis",
"cinco", "cuatro", "tres", "dos", "uno", "cero"]
self.ords = { 1 : "primer",
2 : "segund",
3 : "tercer",
4 : "cuart",
5 : "quint",
6 : "sext",
7 : "s\xE8ptim",
8 : "octav",
9 : "noven",
10 : "d\xE8cim" }
def merge(self, curr, next):
ctext, cnum, ntext, nnum = curr + next
if cnum == 1:
if nnum < 1000000:
return next
ctext = "un"
elif cnum == 100:
ctext += "t" + self.gender_stem
if nnum < cnum:
if cnum < 100:
return ("%s y %s"%(ctext, ntext), cnum + nnum)
return ("%s %s"%(ctext, ntext), cnum + nnum)
elif (not nnum % 1000000) and cnum > 1:
ntext = ntext[:-3] + "ones"
if nnum == 100:
if cnum == 5:
ctext = "quinien"
ntext = ""
elif cnum == 7:
ctext = "sete"
elif cnum == 9:
ctext = "nove"
ntext += "t" + self.gender_stem + "s"
else:
ntext = " " + ntext
return (ctext + ntext, cnum * nnum)
def to_ordinal(self, value):
self.verify_ordinal(value)
try:
return self.ords[value] + self.gender_stem
except KeyError:
return self.to_cardinal(value)
def to_ordinal_num(self, value):
self.verify_ordinal(value)
# Correct for fem?
return "%s\xB0"%value
def to_currency(self, val, longval=True, old=False):
if old:
return self.to_splitnum(val, hightxt="peso/s", lowtxt="peseta/s",
divisor=1000, jointxt="y", longval=longval)
return super(Num2Word_ES, self).to_currency(val, jointxt="y",
longval=longval)
n2w = Num2Word_ES()
to_card = n2w.to_cardinal
to_ord = n2w.to_ordinal
to_ordnum = n2w.to_ordinal_num
def main():
for val in [ 1, 11, 12, 21, 31, 33, 71, 80, 81, 91, 99, 100, 101, 102, 155,
180, 300, 308, 832, 1000, 1001, 1061, 1100, 1500, 1701, 3000,
8280, 8291, 150000, 500000, 1000000, 2000000, 2000001,
-21212121211221211111, -2.121212, -1.0000100]:
n2w.test(val)
n2w.test(1325325436067876801768700107601001012212132143210473207540327057320957032975032975093275093275093270957329057320975093272950730)
print n2w.to_currency(1222)
print n2w.to_currency(1222, old=True)
print n2w.to_year(1222)
if __name__ == "__main__":
main()

44
pynum2word/num2word_EU.py Normal file
View File

@@ -0,0 +1,44 @@
'''
Module: num2word_EU.py
Requires: num2word_base.py
Version: 1.1
Author:
Taro Ogawa (tso@users.sourceforge.org)
Copyright:
Copyright (c) 2003, Taro Ogawa. All Rights Reserved.
Licence:
This module is distributed under the Lesser General Public Licence.
http://www.opensource.org/licenses/lgpl-license.php
Data from:
http://www.uni-bonn.de/~manfear/large.php
History:
1.1: add to_currency()
'''
from num2word_base import Num2Word_Base
class Num2Word_EU(Num2Word_Base):
def set_high_numwords(self, high):
max = 3 + 6*len(high)
for word, n in zip(high, range(max, 3, -6)):
self.cards[10**n] = word + "illiard"
self.cards[10**(n-3)] = word + "illion"
def base_setup(self):
lows = ["non","oct","sept","sext","quint","quadr","tr","b","m"]
units = ["", "un", "duo", "tre", "quattuor", "quin", "sex", "sept",
"octo", "novem"]
tens = ["dec", "vigint", "trigint", "quadragint", "quinquagint",
"sexagint", "septuagint", "octogint", "nonagint"]
self.high_numwords = ["cent"]+self.gen_high_numwords(units, tens, lows)
def to_currency(self, val, longval=True, jointxt=""):
return self.to_splitnum(val, hightxt="Euro/s", lowtxt="Euro cent/s",
jointxt=jointxt, longval=longval)

119
pynum2word/num2word_FR.py Normal file
View File

@@ -0,0 +1,119 @@
'''
Module: num2word_FR.py
Requires: num2word_EU.py
Version: 0.5
Author:
Taro Ogawa (tso@users.sourceforge.org)
Copyright:
Copyright (c) 2003, Taro Ogawa. All Rights Reserved.
Licence:
This module is distributed under the Lesser General Public Licence.
http://www.opensource.org/licenses/lgpl-license.php
Data from:
http://www.ouc.bc.ca/mola/fr/handouts/numbers.doc
http://www.realfrench.net/units/Interunit_63.html
http://www.sover.net/~daxtell/france/Euro/euro.htm
Usage:
from num2word_FR import to_card, to_ord, to_ordnum
to_card(1234567890)
to_ord(1234567890)
to_ordnum(12)
History:
0.5: Use high ascii characters instead of low ascii approximations
String interpolation where it makes things clearer
to_currency() added [to_year works by default]
'''
from num2word_EU import Num2Word_EU
#//TODO: error messages in French
#//TODO: ords
class Num2Word_FR(Num2Word_EU):
def setup(self):
self.negword = "moins "
self.pointword = "virgule"
self.errmsg_nonnum = "Only numbers may be converted to words."
self.errmsg_toobig = "Number is too large to convert to words."
self.exclude_title = ["et", "virgule", "moins"]
self.mid_numwords = [(1000, "mille"), (100, "cent"),
(80, "quatre-vingts"), (60, "soixante"),
(50, "cinquante"), (40, "quarante"),
(30, "trente")]
self.low_numwords = ["vingt", "dix-neuf", "dix-huit", "dix-sept",
"seize", "quinze", "quatorze", "treize", "douze",
"onze", "dix", "neuf", "huit", "sept", "six",
"cinq", "quatre", "trois", "deux", "un", "z\xE8ro"]
def merge(self, curr, next):
ctext, cnum, ntext, nnum = curr + next
if cnum == 1:
if nnum < 1000000:
return next
else:
if (not (cnum - 80)%100 or not cnum%100) and ctext[-1] == "s":
ctext = ctext[:-1]
if (cnum<1000 and nnum <> 1000 and ntext[-1] <> "s"
and not nnum%100):
ntext += "s"
if nnum < cnum < 100:
if nnum % 10 == 1 and cnum <> 80:
return ("%s et %s"%(ctext, ntext), cnum + nnum)
return ("%s-%s"%(ctext, ntext), cnum + nnum)
elif nnum > cnum:
return ("%s %s"%(ctext, ntext), cnum * nnum)
return ("%s %s"%(ctext, ntext), cnum + nnum)
# Is this right for such things as 1001 - "mille uni<6E>me" instead of
# "mille premier"?? "milli<6C>me"??
def to_ordinal(self,value):
self.verify_ordinal(value)
if value == 1:
return "premier"
word = self.to_cardinal(value)
if word[-1] == "e":
word = word[:-1]
return word + "i\xE8me"
def to_ordinal_num(self, value):
self.verify_ordinal(value)
out = str(value)
out += {"1" : "er" }.get(out[-1], "me")
return out
def to_currency(self, val, longval=True, old=False):
hightxt = "Euro/s"
if old:
hightxt="franc/s"
return self.to_splitnum(val, hightxt=hightxt, lowtxt="centime/s",
jointxt="et",longval=longval)
n2w = Num2Word_FR()
to_card = n2w.to_cardinal
to_ord = n2w.to_ordinal
to_ordnum = n2w.to_ordinal_num
def main():
for val in [ 1, 11, 12, 21, 31, 33, 71, 80, 81, 91, 99, 100, 101, 102, 155,
180, 300, 308, 832, 1000, 1001, 1061, 1100, 1500, 1701, 3000,
8280, 8291, 150000, 500000, 1000000, 2000000, 2000001,
-21212121211221211111, -2.121212, -1.0000100]:
n2w.test(val)
n2w.test(1325325436067876801768700107601001012212132143210473207540327057320957032975032975093275093275093270957329057320975093272950730)
print n2w.to_currency(112121)
print n2w.to_year(1996)
if __name__ == "__main__":
main()

213
pynum2word/num2word_LT.py Normal file
View File

@@ -0,0 +1,213 @@
# -*- encoding: utf-8 -*-
u"""
>>> from textwrap import fill
>>> ' '.join([str(i) for i in splitby3('1')])
'1'
>>> ' '.join([str(i) for i in splitby3('1123')])
'1 123'
>>> ' '.join([str(i) for i in splitby3('1234567890')])
'1 234 567 890'
>>> print(' '.join([n2w(i) for i in range(10)]))
nulis vienas du trys keturi penki šeši septyni aštuoni devyni
>>> print(fill(' '.join([n2w(i+10) for i in range(10)])))
dešimt vienuolika dvylika trylika keturiolika penkiolika šešiolika
septyniolika aštuoniolika devyniolika
>>> print(fill(' '.join([n2w(i*10) for i in range(10)])))
nulis dešimt dvidešimt trisdešimt keturiasdešimt penkiasdešimt
šešiasdešimt septyniasdešimt aštuoniasdešimt devyniasdešimt
>>> print(n2w(100))
šimtas
>>> print(n2w(101))
šimtas vienas
>>> print(n2w(110))
šimtas dešimt
>>> print(n2w(115))
šimtas penkiolika
>>> print(n2w(123))
šimtas dvidešimt trys
>>> print(n2w(1000))
tūkstantis
>>> print(n2w(1001))
tūkstantis vienas
>>> print(n2w(2012))
du tūkstančiai dvylika
>>> print(fill(n2w(1234567890)))
milijardas du šimtai trisdešimt keturi milijonai penki šimtai
šešiasdešimt septyni tūkstančiai aštuoni šimtai devyniasdešimt
>>> print(fill(n2w(215461407892039002157189883901676)))
du šimtai penkiolika naintilijonų keturi šimtai šešiasdešimt vienas
oktilijonas keturi šimtai septyni septilijonai aštuoni šimtai
devyniasdešimt du sikstilijonai trisdešimt devyni kvintilijonai du
kvadrilijonai šimtas penkiasdešimt septyni trilijonai šimtas
aštuoniasdešimt devyni milijardai aštuoni šimtai aštuoniasdešimt trys
milijonai devyni šimtai vienas tūkstantis šeši šimtai septyniasdešimt
šeši
>>> print(fill(n2w(719094234693663034822824384220291)))
septyni šimtai devyniolika naintilijonų devyniasdešimt keturi
oktilijonai du šimtai trisdešimt keturi septilijonai šeši šimtai
devyniasdešimt trys sikstilijonai šeši šimtai šešiasdešimt trys
kvintilijonai trisdešimt keturi kvadrilijonai aštuoni šimtai dvidešimt
du trilijonai aštuoni šimtai dvidešimt keturi milijardai trys šimtai
aštuoniasdešimt keturi milijonai du šimtai dvidešimt tūkstančių du
šimtai devyniasdešimt vienas
# TODO: fix this:
>>> print(fill(n2w(1000000000000000000000000000000)))
naintilijonas
>>> print(to_currency(1, 'LTL'))
vienas litas, nulis centų
>>> print(to_currency(1234.56, 'LTL'))
tūkstantis du šimtai trisdešimt keturi litai, penkiasdešimt šeši centai
"""
ZERO = (u'nulis',)
ONES = {
1: (u'vienas',),
2: (u'du',),
3: (u'trys',),
4: (u'keturi',),
5: (u'penki',),
6: (u'šeši',),
7: (u'septyni',),
8: (u'aštuoni',),
9: (u'devyni',),
}
TENS = {
0: (u'dešimt',),
1: (u'vienuolika',),
2: (u'dvylika',),
3: (u'trylika',),
4: (u'keturiolika',),
5: (u'penkiolika',),
6: (u'šešiolika',),
7: (u'septyniolika',),
8: (u'aštuoniolika',),
9: (u'devyniolika',),
}
TWENTIES = {
2: (u'dvidešimt',),
3: (u'trisdešimt',),
4: (u'keturiasdešimt',),
5: (u'penkiasdešimt',),
6: (u'šešiasdešimt',),
7: (u'septyniasdešimt',),
8: (u'aštuoniasdešimt',),
9: (u'devyniasdešimt',),
}
HUNDRED = (u'šimtas', u'šimtai')
THOUSANDS = {
1: (u'tūkstantis', u'tūkstančiai', u'tūkstančių'),
2: (u'milijonas', u'milijonai', u'milijonų'),
3: (u'milijardas', u'milijardai', u'milijardų'),
4: (u'trilijonas', u'trilijonai', u'trilijonų'),
5: (u'kvadrilijonas', u'kvadrilijonai', u'kvadrilijonų'),
6: (u'kvintilijonas', u'kvintilijonai', u'kvintilijonų'),
7: (u'sikstilijonas', u'sikstilijonai', u'sikstilijonų'),
8: (u'septilijonas', u'septilijonai', u'septilijonų'),
9: (u'oktilijonas', u'oktilijonai', u'oktilijonų'),
10: (u'naintilijonas', u'naintilijonai', u'naintilijonų'),
}
CURRENCIES = {
'LTL': ((u'litas', u'litai', u'litų'), (u'centas', u'centai', u'centų')),
}
def splitby3(n):
length = len(n)
if length > 3:
start = length % 3
if start > 0:
yield int(n[:start])
for i in range(start, length, 3):
yield int(n[i:i+3])
else:
yield int(n)
def get_digits(n):
return [int(x) for x in reversed(list(('%03d' % n)[-3:]))]
def pluralize(n, forms):
n1, n2, n3 = get_digits(n)
if n2 == 1 or n1 == 0 or n == 0:
return forms[2]
elif n1 == 1:
return forms[0]
else:
return forms[1]
def int2word(n):
if n == 0:
return ZERO[0]
words = []
chunks = list(splitby3(str(n)))
i = len(chunks)
for x in chunks:
i -= 1
n1, n2, n3 = get_digits(x)
if n3 > 0:
if n3 > 1:
words.append(ONES[n3][0])
words.append(HUNDRED[1])
else:
words.append(HUNDRED[0])
if n2 > 1:
words.append(TWENTIES[n2][0])
if n2 == 1:
words.append(TENS[n1][0])
elif n1 > 0 and not (i > 0 and x == 1):
words.append(ONES[n1][0])
if i > 0:
words.append(pluralize(x, THOUSANDS[i]))
return ' '.join(words)
def n2w(n):
n = str(n).replace(',', '.')
if '.' in n:
left, right = n.split('.')
return u'%s kablelis %s' % (int2word(int(left)), int2word(int(right)))
else:
return int2word(int(n))
def to_currency(n, currency='LTL'):
if type(n) == int:
left = n / 100
right = n % 100
else:
n = str(n).replace(',', '.')
if '.' in n:
left, right = n.split('.')
else:
left, right = n, 0
left, right = int(left), int(right)
cr1, cr2 = CURRENCIES[currency]
return u'%s %s, %s %s' % (int2word(left), pluralize(left, cr1),
int2word(right), pluralize(right, cr2))
to_card = n2w
if __name__ == '__main__':
import doctest
doctest.testmod()

266
pynum2word/num2word_base.py Normal file
View File

@@ -0,0 +1,266 @@
'''
Module: num2word_base.py
Version: 1.0
Author:
Taro Ogawa (tso@users.sourceforge.org)
Copyright:
Copyright (c) 2003, Taro Ogawa. All Rights Reserved.
Licence:
This module is distributed under the Lesser General Public Licence.
http://www.opensource.org/licenses/lgpl-license.php
History:
1.1: add to_splitnum() and inflect()
add to_year() and to_currency() stubs
'''
from __future__ import generators
from orderedmapping import OrderedMapping
class Num2Word_Base(object):
def __init__(self):
self.cards = OrderedMapping()
self.is_title = False
self.precision = 2
self.exclude_title = []
self.negword = "(-) "
self.pointword = "(.)"
self.errmsg_nonnum = "type(%s) not in [long, int, float]"
self.errmsg_floatord = "Cannot treat float %s as ordinal."
self.errmsg_negord = "Cannot treat negative num %s as ordinal."
self.errmsg_toobig = "abs(%s) must be less than %s."
self.base_setup()
self.setup()
self.set_numwords()
self.MAXVAL = 1000 * self.cards.order[0]
def set_numwords(self):
self.set_high_numwords(self.high_numwords)
self.set_mid_numwords(self.mid_numwords)
self.set_low_numwords(self.low_numwords)
def gen_high_numwords(self, units, tens, lows):
out = [u + t for t in tens for u in units]
out.reverse()
return out + lows
def set_mid_numwords(self, mid):
for key, val in mid:
self.cards[key] = val
def set_low_numwords(self, numwords):
for word, n in zip(numwords, range(len(numwords) - 1, -1, -1)):
self.cards[n] = word
def splitnum(self, value):
for elem in self.cards:
if elem > value:
continue
out = []
if value == 0:
div, mod = 1, 0
else:
div, mod = divmod(value, elem)
if div == 1:
out.append((self.cards[1], 1))
else:
if div == value: # The system tallies, eg Roman Numerals
return [(div * self.cards[elem], div*elem)]
out.append(self.splitnum(div))
out.append((self.cards[elem], elem))
if mod:
out.append(self.splitnum(mod))
return out
def to_cardinal(self, value):
try:
assert long(value) == value
except (ValueError, TypeError, AssertionError):
return self.to_cardinal_float(value)
self.verify_num(value)
out = ""
if value < 0:
value = abs(value)
out = self.negword
if value >= self.MAXVAL:
raise OverflowError(self.errmsg_toobig % (value, self.MAXVAL))
val = self.splitnum(value)
words, num = self.clean(val)
return self.title(out + words)
def to_cardinal_float(self, value):
try:
float(value) == value
except (ValueError, TypeError, AssertionError):
raise TypeError(self.errmsg_nonnum % value)
pre = int(value)
post = abs(value - pre)
out = [self.to_cardinal(pre)]
if self.precision:
out.append(self.title(self.pointword))
for i in range(self.precision):
post *= 10
curr = int(post)
out.append(str(self.to_cardinal(curr)))
post -= curr
return " ".join(out)
def merge(self, curr, next):
raise NotImplementedError
def clean(self, val):
out = val
while len(val) != 1:
out = []
left, right = val[:2]
if isinstance(left, tuple) and isinstance(right, tuple):
out.append(self.merge(left, right))
if val[2:]:
out.append(val[2:])
else:
for elem in val:
if isinstance(elem, list):
if len(elem) == 1:
out.append(elem[0])
else:
out.append(self.clean(elem))
else:
out.append(elem)
val = out
return out[0]
def title(self, value):
if self.is_title:
out = []
value = value.split()
for word in value:
if word in self.exclude_title:
out.append(word)
else:
out.append(word[0].upper() + word[1:])
value = " ".join(out)
return value
def verify_ordinal(self, value):
if not value == long(value):
raise TypeError, self.errmsg_floatord %(value)
if not abs(value) == value:
raise TypeError, self.errmsg_negord %(value)
def verify_num(self, value):
return 1
def set_wordnums(self):
pass
def to_ordinal(value):
return self.to_cardinal(value)
def to_ordinal_num(self, value):
return value
# Trivial version
def inflect(self, value, text):
text = text.split("/")
if value == 1:
return text[0]
return "".join(text)
#//CHECK: generalise? Any others like pounds/shillings/pence?
def to_splitnum(self, val, hightxt="", lowtxt="", jointxt="",
divisor=100, longval=True):
out = []
try:
high, low = val
except TypeError:
high, low = divmod(val, divisor)
if high:
hightxt = self.title(self.inflect(high, hightxt))
out.append(self.to_cardinal(high))
if low:
if longval:
if hightxt:
out.append(hightxt)
if jointxt:
out.append(self.title(jointxt))
elif hightxt:
out.append(hightxt)
if low:
out.append(self.to_cardinal(low))
if lowtxt and longval:
out.append(self.title(self.inflect(low, lowtxt)))
return " ".join(out)
def to_year(self, value, **kwargs):
return self.to_cardinal(value)
def to_currency(self, value, **kwargs):
return self.to_cardinal(value)
def base_setup(self):
pass
def setup(self):
pass
def test(self, value):
try:
_card = self.to_cardinal(value)
except:
_card = "invalid"
try:
_ord = self.to_ordinal(value)
except:
_ord = "invalid"
try:
_ordnum = self.to_ordinal_num(value)
except:
_ordnum = "invalid"
print ("For %s, card is %s;\n\tord is %s; and\n\tordnum is %s." %
(value, _card, _ord, _ordnum))

View File

@@ -0,0 +1,34 @@
'''
Module: orderedmapping.py
Version: 1.0
Author:
Taro Ogawa (tso@users.sourceforge.org)
Copyright:
Copyright (c) 2003, Taro Ogawa. All Rights Reserved.
Licence:
This module is distributed under the Lesser General Public Licence.
http://www.opensource.org/licenses/lgpl-license.php
'''
from __future__ import generators
class OrderedMapping(dict):
def __init__(self, *pairs):
self.order = []
for key, val in pairs:
self[key] = val
def __setitem__(self, key, val):
if key not in self:
self.order.append(key)
super(OrderedMapping, self).__setitem__(key, val)
def __iter__(self):
for item in self.order:
yield item
def __repr__(self):
out = ["%s: %s"%(repr(item), repr(self[item])) for item in self]
out = ", ".join(out)
return "{%s}"%out