From f1e887bcd2ba9a1e068d2323efd78bfaa705c7d1 Mon Sep 17 00:00:00 2001 From: tso Date: Thu, 17 Jul 2003 01:37:11 +0000 Subject: [PATCH] Initial revision --- num2word.py | 55 +++++++++++ num2word_DE.py | 134 ++++++++++++++++++++++++++ num2word_EN.py | 113 ++++++++++++++++++++++ num2word_EN_old.py | 46 +++++++++ num2word_ES.py | 132 +++++++++++++++++++++++++ num2word_EU.py | 36 +++++++ num2word_FR.py | 103 ++++++++++++++++++++ num2word_base.py | 235 +++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 854 insertions(+) create mode 100644 num2word.py create mode 100644 num2word_DE.py create mode 100644 num2word_EN.py create mode 100644 num2word_EN_old.py create mode 100644 num2word_ES.py create mode 100644 num2word_EU.py create mode 100644 num2word_FR.py create mode 100644 num2word_base.py diff --git a/num2word.py b/num2word.py new file mode 100644 index 0000000..597708e --- /dev/null +++ b/num2word.py @@ -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))) diff --git a/num2word_DE.py b/num2word_DE.py new file mode 100644 index 0000000..4ea77c0 --- /dev/null +++ b/num2word_DE.py @@ -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() + diff --git a/num2word_EN.py b/num2word_EN.py new file mode 100644 index 0000000..0239e29 --- /dev/null +++ b/num2word_EN.py @@ -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() diff --git a/num2word_EN_old.py b/num2word_EN_old.py new file mode 100644 index 0000000..94d644c --- /dev/null +++ b/num2word_EN_old.py @@ -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() diff --git a/num2word_ES.py b/num2word_ES.py new file mode 100644 index 0000000..7eb29ea --- /dev/null +++ b/num2word_ES.py @@ -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() diff --git a/num2word_EU.py b/num2word_EU.py new file mode 100644 index 0000000..9cf0fcb --- /dev/null +++ b/num2word_EU.py @@ -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) diff --git a/num2word_FR.py b/num2word_FR.py new file mode 100644 index 0000000..5055bf3 --- /dev/null +++ b/num2word_FR.py @@ -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() diff --git a/num2word_base.py b/num2word_base.py new file mode 100644 index 0000000..6c7beb7 --- /dev/null +++ b/num2word_base.py @@ -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))