mirror of
https://github.com/bblaz/num2words.git
synced 2025-12-06 06:42:25 +00:00
Initial revision
This commit is contained in:
55
num2word.py
Normal file
55
num2word.py
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
'''
|
||||||
|
Module: num2word.py
|
||||||
|
Requires: num2word_*.py
|
||||||
|
Version: 0.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
|
||||||
|
|
||||||
|
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.
|
||||||
|
'''
|
||||||
|
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:
|
||||||
|
n2w = __import__(_module)
|
||||||
|
break
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
to_card, to_ord, to_ordnum = n2w.to_card, n2w.to_ord, n2w.to_ordnum
|
||||||
|
except NameError:
|
||||||
|
raise ImportError("Could not import any of these modules: %s"
|
||||||
|
% (", ".join(_modules)))
|
||||||
134
num2word_DE.py
Normal file
134
num2word_DE.py
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
'''
|
||||||
|
Module: num2word_DE.py
|
||||||
|
Requires: num2word_base.py
|
||||||
|
Version: 0.4
|
||||||
|
|
||||||
|
Author:
|
||||||
|
Taro Ogawa (BLAHhydroxideBLAH_removetheBLAHs@inorbit.com)
|
||||||
|
|
||||||
|
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)
|
||||||
|
'''
|
||||||
|
from num2word_base import Num2Word_Base
|
||||||
|
|
||||||
|
#//TODO: Use orthographics
|
||||||
|
#//TODO: Use German error messages
|
||||||
|
class Num2Word_DE(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 + "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, "fuenfzig"), (40, "vierzig"),
|
||||||
|
(30, "dreissig")]
|
||||||
|
self.low_numwords = ["zwanzig", "neunzehn", "achtzen", "siebzehn",
|
||||||
|
"sechzehn", "fuenfzehn", "vierzehn", "dreizehn",
|
||||||
|
"zwoelf", "elf", "zehn", "neun", "acht", "sieben",
|
||||||
|
"sechs", "fuenf", "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"
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
||||||
113
num2word_EN.py
Normal file
113
num2word_EN.py
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
'''
|
||||||
|
Module: num2word_EN.py
|
||||||
|
Requires: num2word_EU.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)
|
||||||
|
'''
|
||||||
|
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_nonnum = "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, curr, next):
|
||||||
|
ctext, cnum, ntext, nnum = curr + next
|
||||||
|
|
||||||
|
if cnum == 1 and nnum < 100:
|
||||||
|
return next
|
||||||
|
elif 100 > cnum > nnum :
|
||||||
|
return (ctext + "-" + ntext, cnum + nnum)
|
||||||
|
elif cnum >= 100 > nnum:
|
||||||
|
return (ctext + " and " + ntext, cnum + nnum)
|
||||||
|
elif nnum > cnum:
|
||||||
|
return (ctext + " " + ntext, cnum * nnum)
|
||||||
|
return (ctext + ", " + ntext, cnum + nnum)
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
out = str(value)
|
||||||
|
out += {"1" : "st",
|
||||||
|
"2" : "nd",
|
||||||
|
"3" : "rd" }.get(out[-1], "th")
|
||||||
|
return out
|
||||||
|
|
||||||
|
n2w = Num2Word_EN()
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
46
num2word_EN_old.py
Normal file
46
num2word_EN_old.py
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
'''
|
||||||
|
Module: num2word_EN_old.py
|
||||||
|
Requires: num2word_EN.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)
|
||||||
|
'''
|
||||||
|
import num2word_EN
|
||||||
|
|
||||||
|
class Num2Word_EN_old(num2word_EN.Num2Word_EN):
|
||||||
|
def base_setup(self):
|
||||||
|
sclass = super(num2word_EN.Num2Word_EN, self)
|
||||||
|
self.set_high_numwords = sclass.set_high_numwords
|
||||||
|
sclass.base_setup()
|
||||||
|
|
||||||
|
|
||||||
|
n2w = Num2Word_EN_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)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
132
num2word_ES.py
Normal file
132
num2word_ES.py
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
'''
|
||||||
|
Module: num2word_ES.py
|
||||||
|
Requires: num2word_EU.py
|
||||||
|
Version: 0.2
|
||||||
|
|
||||||
|
Author:
|
||||||
|
Taro Ogawa (BLAHhydroxideBLAH@inorbit.removeBLAHtwice.com)
|
||||||
|
|
||||||
|
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)
|
||||||
|
'''
|
||||||
|
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 + "illo'n"
|
||||||
|
|
||||||
|
|
||||||
|
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",
|
||||||
|
"vientise'is", "vienticinco", "vienticuatro",
|
||||||
|
"vientitre's", "vientido's", "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 : "se'ptim",
|
||||||
|
8 : "octav",
|
||||||
|
9 : "noven",
|
||||||
|
10 : "de'cim" }
|
||||||
|
|
||||||
|
|
||||||
|
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 (ctext + " y " + ntext, cnum + nnum)
|
||||||
|
return (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 str(value) + "^o"
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
36
num2word_EU.py
Normal file
36
num2word_EU.py
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
'''
|
||||||
|
Module: num2word_EU.py
|
||||||
|
Requires: num2word_base.py
|
||||||
|
Version: 1.0
|
||||||
|
|
||||||
|
Author:
|
||||||
|
Taro Ogawa (BLAHhydroxideBLAH@inorbit.removeBLAHtwice.com)
|
||||||
|
|
||||||
|
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
|
||||||
|
'''
|
||||||
|
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)
|
||||||
103
num2word_FR.py
Normal file
103
num2word_FR.py
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
'''
|
||||||
|
Module: num2word_FR.py
|
||||||
|
Requires: num2word_EU.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://www.ouc.bc.ca/mola/fr/handouts/numbers.doc.
|
||||||
|
http://www.realfrench.net/units/Interunit_63.html
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
from num2word_FR import to_card, to_ord, to_ordnum
|
||||||
|
to_card(1234567890)
|
||||||
|
# to_ord(1234567890)
|
||||||
|
# to_ordnum(12)
|
||||||
|
'''
|
||||||
|
from num2word_EU import Num2Word_EU
|
||||||
|
|
||||||
|
#//TODO: correct orthographics
|
||||||
|
#//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", "ze'ro"]
|
||||||
|
|
||||||
|
|
||||||
|
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 (ctext + " et " + ntext, cnum + nnum)
|
||||||
|
return (ctext + "-" + ntext, cnum + nnum)
|
||||||
|
elif nnum > cnum:
|
||||||
|
return (ctext + " " + ntext, cnum * nnum)
|
||||||
|
return (ctext + " " + ntext, cnum + nnum)
|
||||||
|
|
||||||
|
|
||||||
|
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 + "ie'me"
|
||||||
|
|
||||||
|
|
||||||
|
def to_ordinal_num(self, value):
|
||||||
|
self.verify_ordinal(value)
|
||||||
|
out = str(value)
|
||||||
|
out += {"1" : "er" }.get(out[-1], "me")
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
235
num2word_base.py
Normal file
235
num2word_base.py
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
'''
|
||||||
|
Module: num2word_base.py
|
||||||
|
Version: 1.0
|
||||||
|
|
||||||
|
Author:
|
||||||
|
Taro Ogawa (BLAHhydroxideBLAH_removetheBLAHs@inorbit.com)
|
||||||
|
|
||||||
|
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
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
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 = []
|
||||||
|
curr, next = val[:2]
|
||||||
|
if isinstance(curr, tuple) and isinstance(next, tuple):
|
||||||
|
out.append(self.merge(curr, next))
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
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))
|
||||||
Reference in New Issue
Block a user