mirror of
https://github.com/bblaz/num2words.git
synced 2025-12-06 06:42:25 +00:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
@@ -20,22 +20,38 @@ from . import lang_EN
|
||||
from . import lang_EN_GB
|
||||
from . import lang_EN_IN
|
||||
from . import lang_FR
|
||||
from . import lang_FR_CH
|
||||
from . import lang_DE
|
||||
from . import lang_ES
|
||||
from . import lang_LT
|
||||
from . import lang_LV
|
||||
from . import lang_PL
|
||||
from . import lang_RU
|
||||
from . import lang_ID
|
||||
from . import lang_NO
|
||||
from . import lang_DK
|
||||
from . import lang_PT_BR
|
||||
from . import lang_HE
|
||||
from . import lang_IT
|
||||
|
||||
CONVERTER_CLASSES = {
|
||||
'en': lang_EN.Num2Word_EN(),
|
||||
'en_GB': lang_EN_GB.Num2Word_EN_GB(),
|
||||
'en_IN': lang_EN_IN.Num2Word_EN_IN(),
|
||||
'fr': lang_FR.Num2Word_FR(),
|
||||
'fr_CH': lang_FR_CH.Num2Word_FR_CH(),
|
||||
'de': lang_DE.Num2Word_DE(),
|
||||
'es': lang_ES.Num2Word_ES(),
|
||||
'id': lang_ID.Num2Word_ID(),
|
||||
'lt': lang_LT.Num2Word_LT(),
|
||||
'lv': lang_LV.Num2Word_LV(),
|
||||
'pl': lang_PL.Num2Word_PL(),
|
||||
'ru': lang_RU.Num2Word_RU(),
|
||||
'no': lang_NO.Num2Word_NO(),
|
||||
'dk': lang_DK.Num2Word_DK(),
|
||||
'pt_BR': lang_PT_BR.Num2Word_PT_BR(),
|
||||
'he': lang_HE.Num2Word_HE(),
|
||||
'it': lang_IT.Num2Word_IT()
|
||||
}
|
||||
|
||||
def num2words(number, ordinal=False, lang='en'):
|
||||
|
||||
@@ -15,7 +15,11 @@
|
||||
# MA 02110-1301 USA
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import math
|
||||
|
||||
from .orderedmapping import OrderedMapping
|
||||
from .compat import to_s
|
||||
|
||||
|
||||
class Num2Word_Base(object):
|
||||
@@ -36,7 +40,7 @@ class Num2Word_Base(object):
|
||||
self.set_numwords()
|
||||
|
||||
self.MAXVAL = 1000 * self.cards.order[0]
|
||||
|
||||
|
||||
|
||||
def set_numwords(self):
|
||||
self.set_high_numwords(self.high_numwords)
|
||||
@@ -64,7 +68,7 @@ class Num2Word_Base(object):
|
||||
for elem in self.cards:
|
||||
if elem > value:
|
||||
continue
|
||||
|
||||
|
||||
out = []
|
||||
if value == 0:
|
||||
div, mod = 1, 0
|
||||
@@ -75,7 +79,7 @@ class Num2Word_Base(object):
|
||||
out.append((self.cards[1], 1))
|
||||
else:
|
||||
if div == value: # The system tallies, eg Roman Numerals
|
||||
return [(div * self.cards[elem], div*elem)]
|
||||
return [(div * self.cards[elem], div*elem)]
|
||||
out.append(self.splitnum(div))
|
||||
|
||||
out.append((self.cards[elem], elem))
|
||||
@@ -88,7 +92,7 @@ class Num2Word_Base(object):
|
||||
|
||||
def to_cardinal(self, value):
|
||||
try:
|
||||
assert long(value) == value
|
||||
assert int(value) == value
|
||||
except (ValueError, TypeError, AssertionError):
|
||||
return self.to_cardinal_float(value)
|
||||
|
||||
@@ -101,7 +105,6 @@ class Num2Word_Base(object):
|
||||
|
||||
if value >= self.MAXVAL:
|
||||
raise OverflowError(self.errmsg_toobig % (value, self.MAXVAL))
|
||||
|
||||
|
||||
val = self.splitnum(value)
|
||||
words, num = self.clean(val)
|
||||
@@ -114,18 +117,26 @@ class Num2Word_Base(object):
|
||||
except (ValueError, TypeError, AssertionError):
|
||||
raise TypeError(self.errmsg_nonnum % value)
|
||||
|
||||
value = float(value)
|
||||
pre = int(value)
|
||||
post = abs(value - pre)
|
||||
post = abs(value - pre) * 10**self.precision
|
||||
if abs(round(post) - post) < 0.01:
|
||||
# We generally floor all values beyond our precision (rather than rounding), but in
|
||||
# cases where we have something like 1.239999999, which is probably due to python's
|
||||
# handling of floats, we actually want to consider it as 1.24 instead of 1.23
|
||||
post = int(round(post))
|
||||
else:
|
||||
post = int(math.floor(post))
|
||||
post = str(post)
|
||||
post = '0' * (self.precision - len(post)) + post
|
||||
|
||||
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
|
||||
curr = int(post[i])
|
||||
out.append(to_s(self.to_cardinal(curr)))
|
||||
|
||||
return " ".join(out)
|
||||
|
||||
@@ -170,10 +181,10 @@ class Num2Word_Base(object):
|
||||
|
||||
|
||||
def verify_ordinal(self, value):
|
||||
if not value == long(value):
|
||||
raise TypeError, self.errmsg_floatord %(value)
|
||||
if not value == int(value):
|
||||
raise TypeError(self.errmsg_floatord % value)
|
||||
if not abs(value) == value:
|
||||
raise TypeError, self.errmsg_negord %(value)
|
||||
raise TypeError(self.errmsg_negord % value)
|
||||
|
||||
|
||||
def verify_num(self, value):
|
||||
@@ -183,8 +194,8 @@ class Num2Word_Base(object):
|
||||
def set_wordnums(self):
|
||||
pass
|
||||
|
||||
|
||||
def to_ordinal(value):
|
||||
|
||||
def to_ordinal(self, value):
|
||||
return self.to_cardinal(value)
|
||||
|
||||
|
||||
@@ -260,6 +271,6 @@ class Num2Word_Base(object):
|
||||
_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))
|
||||
|
||||
26
num2words/compat.py
Normal file
26
num2words/compat.py
Normal file
@@ -0,0 +1,26 @@
|
||||
# Copyright (c) 2003, Taro Ogawa. All Rights Reserved.
|
||||
# Copyright (c) 2016, Savoir-faire Linux inc. All Rights Reserved.
|
||||
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
# MA 02110-1301 USA
|
||||
|
||||
import sys
|
||||
|
||||
PY3 = sys.version_info[0] == 3
|
||||
|
||||
def to_s(val):
|
||||
if PY3:
|
||||
return str(val)
|
||||
else:
|
||||
return unicode(val)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2003, Taro Ogawa. All Rights Reserved.
|
||||
# Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved.
|
||||
|
||||
@@ -14,10 +15,9 @@
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
# MA 02110-1301 USA
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from __future__ import unicode_literals, print_function
|
||||
from .lang_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)
|
||||
@@ -26,12 +26,13 @@ class Num2Word_DE(Num2Word_EU):
|
||||
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.errmsg_floatord = "Die Gleitkommazahl %s kann nicht in eine Ordnungszahl konvertiert werden." # "Cannot treat float %s as ordinal."
|
||||
self.errmsg_nonnum = "Nur Zahlen (type(%s)) können in Wörter konvertiert werden." # "type(((type(%s)) ) not in [long, int, float]"
|
||||
self.errmsg_negord = "Die negative Zahl %s kann nicht in eine Ordnungszahl konvertiert werden." # "Cannot treat negative num %s as ordinal."
|
||||
self.errmsg_toobig = "Die Zahl %s muss kleiner als %s sein." # "abs(%s) must be less than %s."
|
||||
self.exclude_title = []
|
||||
|
||||
lows = ["non", "okt", "sept", "sext", "quint", "quadr", "tr", "b", "m"]
|
||||
@@ -44,66 +45,64 @@ class Num2Word_DE(Num2Word_EU):
|
||||
(90, "neunzig"), (80, "achtzig"), (70, "siebzig"),
|
||||
(60, "sechzig"), (50, "f\xFCnfzig"), (40, "vierzig"),
|
||||
(30, "drei\xDFig")]
|
||||
self.low_numwords = ["zwanzig", "neunzehn", "achtzen", "siebzehn",
|
||||
self.low_numwords = ["zwanzig", "neunzehn", "achtzehn", "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
|
||||
|
||||
self.ords = {"eins": "ers",
|
||||
"drei": "drit",
|
||||
"acht": "ach",
|
||||
"sieben": "sieb",
|
||||
"ig": "igs",
|
||||
"ert": "erts",
|
||||
"end": "ends",
|
||||
"ion": "ions",
|
||||
"nen": "nens",
|
||||
"rde": "rdes",
|
||||
"rden": "rdens"}
|
||||
|
||||
def merge(self, curr, next):
|
||||
ctext, cnum, ntext, nnum = curr + next
|
||||
|
||||
if cnum == 1:
|
||||
if nnum < 10**6 or self.ordflag:
|
||||
if nnum < 10**6:
|
||||
return next
|
||||
ctext = "eine"
|
||||
|
||||
if nnum > cnum:
|
||||
if nnum >= 10**6:
|
||||
if cnum > 1:
|
||||
if ntext.endswith("e") or self.ordflag:
|
||||
ntext += "s"
|
||||
if ntext.endswith("e"):
|
||||
ntext += "n"
|
||||
else:
|
||||
ntext += "es"
|
||||
ntext += "en"
|
||||
ctext += " "
|
||||
val = cnum * nnum
|
||||
else:
|
||||
if nnum < 10 < cnum < 100:
|
||||
if nnum == 1:
|
||||
ntext = "ein"
|
||||
ntext, ctext = ctext, ntext + "und"
|
||||
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"
|
||||
|
||||
return str(value) + "."
|
||||
|
||||
def to_currency(self, val, longval=True, old=False):
|
||||
if old:
|
||||
@@ -117,8 +116,6 @@ class Num2Word_DE(Num2Word_EU):
|
||||
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
|
||||
@@ -126,15 +123,20 @@ 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,
|
||||
for val in [1, 7, 8, 12, 17, 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,
|
||||
8280, 8291, 150000, 500000, 3000000, 1000000, 2000001, 1000000000, 2000000000,
|
||||
-21212121211221211111, -2.121212, -1.0000100]:
|
||||
n2w.test(val)
|
||||
|
||||
n2w.test(1325325436067876801768700107601001012212132143210473207540327057320957032975032975093275093275093270957329057320975093272950730)
|
||||
print n2w.to_currency(112121)
|
||||
print n2w.to_year(2000)
|
||||
# n2w.test(1325325436067876801768700107601001012212132143210473207540327057320957032975032975093275093275093270957329057320975093272950730)
|
||||
n2w.test(3000000)
|
||||
n2w.test(3000000000001)
|
||||
n2w.test(3000000324566)
|
||||
print(n2w.to_currency(112121))
|
||||
print(n2w.to_year(2000))
|
||||
print(n2w.to_year(1820))
|
||||
print(n2w.to_year(2001))
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
154
num2words/lang_DK.py
Normal file
154
num2words/lang_DK.py
Normal file
@@ -0,0 +1,154 @@
|
||||
# Copyright (c) 2003, Taro Ogawa. All Rights Reserved.
|
||||
# Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved.
|
||||
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
# MA 02110-1301 USA
|
||||
|
||||
from __future__ import division, unicode_literals, print_function
|
||||
from num2words import lang_EU
|
||||
|
||||
class Num2Word_DK(lang_EU.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 + "illarder"
|
||||
self.cards[10**(n-3)] = word + "illioner"
|
||||
|
||||
def setup(self):
|
||||
self.negword = "minus "
|
||||
self.pointword = "komma"
|
||||
self.errmsg_nornum = "Kun tal kan blive konverteret til ord."
|
||||
self.exclude_title = ["og", "komma", "minus"]
|
||||
|
||||
self.mid_numwords = [(1000, "tusind"), (100, "hundrede"),
|
||||
(90, "halvfems"), (80, "firs"), (70, "halvfjerds"),
|
||||
(60, "treds"), (50, "halvtreds"), (40, "fyrre"),
|
||||
(30, "tredive")]
|
||||
self.low_numwords = ["tyve", "nitten", "atten", "sytten",
|
||||
"seksten", "femten", "fjorten", "tretten",
|
||||
"tolv", "elleve", "ti", "ni", "otte",
|
||||
"syv", "seks", "fem", "fire", "tre", "to",
|
||||
"et", "nul"]
|
||||
self.ords = { "nul" : "nul",
|
||||
"et" : "f\xf8rste",
|
||||
"to" : "anden",
|
||||
"tre" : "tredje",
|
||||
"fire" : "fjerde",
|
||||
"fem" : "femte",
|
||||
"seks" : "sjette",
|
||||
"syv" : "syvende",
|
||||
"otte" : "ottende",
|
||||
"ni" : "niende",
|
||||
"ti" : "tiende",
|
||||
"elleve" : "ellevte",
|
||||
"tolv" : "tolvte",
|
||||
"tretten" : "trett",
|
||||
"fjorten" : "fjort",
|
||||
"femten" : "femt",
|
||||
"seksten" : "sekst",
|
||||
"sytten" : "sytt",
|
||||
"atten" : "att",
|
||||
"nitten" : "nitt",
|
||||
"tyve" : "tyv"}
|
||||
|
||||
def merge(self, curr, next):
|
||||
ctext, cnum, ntext, nnum = curr + next
|
||||
if next[1] == 100 or next[1] == 1000:
|
||||
lst = list(next)
|
||||
lst[0] = 'et' + lst[0]
|
||||
next = tuple(lst)
|
||||
|
||||
if cnum == 1:
|
||||
if nnum < 10**6 or self.ordflag:
|
||||
return next
|
||||
ctext = "en"
|
||||
if nnum > cnum:
|
||||
if nnum >= 10**6:
|
||||
ctext += " "
|
||||
val = cnum * nnum
|
||||
else:
|
||||
if cnum >= 100 and cnum < 1000:
|
||||
ctext += " og "
|
||||
elif cnum >= 1000 and cnum <= 100000:
|
||||
ctext += "e og "
|
||||
if nnum < 10 < cnum < 100:
|
||||
if nnum == 1:
|
||||
ntext = "en"
|
||||
ntext, ctext = ctext, ntext + "og"
|
||||
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
|
||||
if value %100 >= 30 and value %100 <= 39 or value %100 == 0:
|
||||
outword += "te"
|
||||
elif value % 100 > 12 or value %100 == 0:
|
||||
outword += "ende"
|
||||
return outword
|
||||
|
||||
def to_ordinal_num(self, value):
|
||||
self.verify_ordinal(value)
|
||||
vaerdte = (0,1,5,6,11,12)
|
||||
if value %100 >= 30 and value %100 <= 39 or value % 100 in vaerdte:
|
||||
return str(value) + "te"
|
||||
elif value % 100 == 2:
|
||||
return str(value) + "en"
|
||||
return str(value) + "ende"
|
||||
|
||||
|
||||
def to_currency(self, val, longval=True):
|
||||
if val//100 == 1 or val == 1:
|
||||
ret = self.to_splitnum(val, hightxt="kr", lowtxt="\xf8re",
|
||||
jointxt="og",longval=longval)
|
||||
return "en " + ret[3:]
|
||||
return self.to_splitnum(val, hightxt="kr", lowtxt="\xf8re",
|
||||
jointxt="og",longval=longval)
|
||||
|
||||
def to_year(self, val, longval=True):
|
||||
if val == 1:
|
||||
return 'en'
|
||||
if not (val//100)%10:
|
||||
return self.to_cardinal(val)
|
||||
return self.to_splitnum(val, hightxt="hundrede", longval=longval)
|
||||
|
||||
n2w = Num2Word_DK()
|
||||
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, 160, 1000,1120,1800, 1976,2000,2010,2099,2171]:
|
||||
print(val, "er", n2w.to_currency(val))
|
||||
print(val, "er", n2w.to_year(val))
|
||||
n2w.test(65132)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -14,7 +14,7 @@
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
# MA 02110-1301 USA
|
||||
|
||||
from __future__ import division, unicode_literals
|
||||
from __future__ import division, unicode_literals, print_function
|
||||
from . import lang_EU
|
||||
|
||||
class Num2Word_EN(lang_EU.Num2Word_EU):
|
||||
@@ -47,7 +47,9 @@ class Num2Word_EN(lang_EU.Num2Word_EU):
|
||||
"twelve" : "twelfth" }
|
||||
|
||||
|
||||
def merge(self, (ltext, lnum), (rtext, rnum)):
|
||||
def merge(self, lpair, rpair):
|
||||
ltext, lnum = lpair
|
||||
rtext, rnum = rpair
|
||||
if lnum == 1 and rnum < 100:
|
||||
return (rtext, rnum)
|
||||
elif 100 > lnum > rnum :
|
||||
@@ -68,9 +70,9 @@ class Num2Word_EN(lang_EU.Num2Word_EU):
|
||||
lastword = self.ords[lastword]
|
||||
except KeyError:
|
||||
if lastword[-1] == "y":
|
||||
lastword = lastword[:-1] + "ie"
|
||||
lastword = lastword[:-1] + "ie"
|
||||
lastword += "th"
|
||||
lastwords[-1] = self.title(lastword)
|
||||
lastwords[-1] = self.title(lastword)
|
||||
outwords[-1] = "-".join(lastwords)
|
||||
return " ".join(outwords)
|
||||
|
||||
@@ -105,9 +107,9 @@ def main():
|
||||
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)
|
||||
|
||||
print(val, "is", n2w.to_currency(val))
|
||||
print(val, "is", n2w.to_year(val))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
# MA 02110-1301 USA
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from __future__ import unicode_literals, print_function
|
||||
from .lang_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",
|
||||
@@ -38,9 +38,9 @@ def main():
|
||||
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)
|
||||
|
||||
print(val, "is", n2w.to_currency(val))
|
||||
print(val, "is", n2w.to_year(val))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
# MA 02110-1301 USA
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from __future__ import unicode_literals, print_function
|
||||
from .lang_EU import Num2Word_EU
|
||||
|
||||
class Num2Word_ES(Num2Word_EU):
|
||||
@@ -173,9 +173,9 @@ def main():
|
||||
n2w.test(val)
|
||||
|
||||
n2w.test(1325325436067876801768700107601001012212132143210473207540327057320957032975032975093275093275093270957329057320975093272950730)
|
||||
print n2w.to_currency(1222)
|
||||
print n2w.to_currency(1222, old=True)
|
||||
print n2w.to_year(1222)
|
||||
print(n2w.to_currency(1222))
|
||||
print(n2w.to_currency(1222, old=True))
|
||||
print(n2w.to_year(1222))
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -15,16 +15,16 @@
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
# MA 02110-1301 USA
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from __future__ import unicode_literals, print_function
|
||||
from .lang_EU import Num2Word_EU
|
||||
|
||||
#//TODO: error messages in French
|
||||
|
||||
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.errmsg_nonnum = u"Seulement des nombres peuvent être convertis en mots."
|
||||
self.errmsg_toobig = u"Nombre trop grand pour être converti en mots."
|
||||
self.exclude_title = ["et", "virgule", "moins"]
|
||||
self.mid_numwords = [(1000, "mille"), (100, "cent"),
|
||||
(80, "quatre-vingts"), (60, "soixante"),
|
||||
@@ -106,8 +106,8 @@ def main():
|
||||
n2w.test(val)
|
||||
|
||||
n2w.test(1325325436067876801768700107601001012212132143210473207540327057320957032975032975093275093275093270957329057320975093272950730)
|
||||
print n2w.to_currency(112121)
|
||||
print n2w.to_year(1996)
|
||||
print(n2w.to_currency(112121))
|
||||
print(n2w.to_year(1996))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
109
num2words/lang_FR_CH.py
Normal file
109
num2words/lang_FR_CH.py
Normal file
@@ -0,0 +1,109 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Copyright (c) 2003, Taro Ogawa. All Rights Reserved.
|
||||
# Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved.
|
||||
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
# MA 02110-1301 USA
|
||||
|
||||
from __future__ import unicode_literals, print_function
|
||||
from .lang_EU import Num2Word_EU
|
||||
|
||||
class Num2Word_FR_CH(Num2Word_EU):
|
||||
def setup(self):
|
||||
self.negword = "moins "
|
||||
self.pointword = "virgule"
|
||||
self.errmsg_nonnum = u"Seulement des nombres peuvent être convertis en mots."
|
||||
self.errmsg_toobig = u"Nombre trop grand pour être converti en mots."
|
||||
self.exclude_title = ["et", "virgule", "moins"]
|
||||
self.mid_numwords = [(1000, "mille"), (100, "cent"), (90, "nonante"),
|
||||
(80, "huitante"), (70, "septante"), (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éro"]
|
||||
self.ords = {
|
||||
"cinq": "cinquième",
|
||||
"neuf": "neuvième",
|
||||
}
|
||||
|
||||
|
||||
def merge(self, curr, next):
|
||||
ctext, cnum, ntext, nnum = curr + next
|
||||
|
||||
if cnum == 1:
|
||||
if nnum < 1000000:
|
||||
return next
|
||||
if cnum < 1000 and nnum != 1000 and ntext[-1] != "s" and not nnum % 100:
|
||||
ntext += "s"
|
||||
|
||||
if nnum < cnum < 100:
|
||||
if nnum % 10 == 1:
|
||||
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ème" instead of
|
||||
# "mille premier"?? "millième"??
|
||||
|
||||
def to_ordinal(self,value):
|
||||
self.verify_ordinal(value)
|
||||
if value == 1:
|
||||
return "premier"
|
||||
word = self.to_cardinal(value)
|
||||
for src, repl in self.ords.items():
|
||||
if word.endswith(src):
|
||||
word = word[:-len(src)] + repl
|
||||
break
|
||||
else:
|
||||
if word[-1] == "e":
|
||||
word = word[:-1]
|
||||
word = word + "ième"
|
||||
return word
|
||||
|
||||
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_CH()
|
||||
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()
|
||||
162
num2words/lang_HE.py
Normal file
162
num2words/lang_HE.py
Normal file
@@ -0,0 +1,162 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Copyright (c) 2003, Taro Ogawa. All Rights Reserved.
|
||||
# Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved.
|
||||
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
# MA 02110-1301 USA
|
||||
|
||||
|
||||
from __future__ import unicode_literals, print_function
|
||||
|
||||
ZERO = (u'אפס',)
|
||||
|
||||
ONES = {
|
||||
1: (u'אחד',),
|
||||
2: (u'שנים',),
|
||||
3: (u'שלש',),
|
||||
4: (u'ארבע',),
|
||||
5: (u'חמש',),
|
||||
6: (u'שש',),
|
||||
7: (u'שבע',),
|
||||
8: (u'שמנה',),
|
||||
9: (u'תשע',),
|
||||
}
|
||||
|
||||
TENS = {
|
||||
0: (u'עשר',),
|
||||
1: (u'אחד עשרה',),
|
||||
2: (u'שנים עשרה',),
|
||||
3: (u'שלש עשרה',),
|
||||
4: (u'ארבע עשרה',),
|
||||
5: (u'חמש עשרה',),
|
||||
6: (u'שש עשרה',),
|
||||
7: (u'שבע עשרה',),
|
||||
8: (u'שמנה עשרה',),
|
||||
9: (u'תשע עשרה',),
|
||||
}
|
||||
|
||||
TWENTIES = {
|
||||
2: (u'עשרים',),
|
||||
3: (u'שלשים',),
|
||||
4: (u'ארבעים',),
|
||||
5: (u'חמישים',),
|
||||
6: (u'ששים',),
|
||||
7: (u'שבעים',),
|
||||
8: (u'שמנים',),
|
||||
9: (u'תשעים',),
|
||||
}
|
||||
|
||||
HUNDRED = {
|
||||
1: (u'מאה',),
|
||||
2: (u'מאתיים',),
|
||||
3: (u'מאות',)
|
||||
}
|
||||
|
||||
THOUSANDS = {
|
||||
1: (u'אלף',),
|
||||
2: (u'אלפיים',),
|
||||
}
|
||||
|
||||
AND = u'ו'
|
||||
|
||||
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):
|
||||
# gettext implementation:
|
||||
# (n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2)
|
||||
|
||||
form = 0 if (n % 10 == 1 and n % 100 != 11) else 1 if n != 0 else 2
|
||||
|
||||
return forms[form]
|
||||
|
||||
|
||||
def int2word(n):
|
||||
if n > 9999: #doesn't yet work for numbers this big
|
||||
raise NotImplementedError()
|
||||
|
||||
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)
|
||||
|
||||
# print str(n3) + str(n2) + str(n1)
|
||||
|
||||
if n3 > 0:
|
||||
if n3 <= 2:
|
||||
words.append(HUNDRED[n3][0])
|
||||
else:
|
||||
words.append(ONES[n3][0])
|
||||
words.append(HUNDRED[3][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:
|
||||
if i <= 2:
|
||||
words.append(THOUSANDS[i][0])
|
||||
else:
|
||||
words.append(ONES[i][0])
|
||||
words.append(THOUSANDS[1][0])
|
||||
|
||||
if len(words) > 1:
|
||||
words[-1] = AND + words[-1]
|
||||
return ' '.join(words)
|
||||
|
||||
|
||||
def n2w(n):
|
||||
return int2word(int(n))
|
||||
|
||||
|
||||
def to_currency(n, currency='EUR', cents=True, seperator=','):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class Num2Word_HE(object):
|
||||
def to_cardinal(self, number):
|
||||
return n2w(number)
|
||||
|
||||
def to_ordinal(self, number):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
yo = Num2Word_HE()
|
||||
nums = [1, 11, 21, 24, 99, 100, 101, 200, 211, 345, 1000, 1011]
|
||||
for num in nums:
|
||||
print(num, yo.to_cardinal(num))
|
||||
|
||||
196
num2words/lang_ID.py
Normal file
196
num2words/lang_ID.py
Normal file
@@ -0,0 +1,196 @@
|
||||
# Copyright (c) 2003, Taro Ogawa. All Rights Reserved.
|
||||
# Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved.
|
||||
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
# MA 02110-1301 USA
|
||||
|
||||
from __future__ import unicode_literals, print_function
|
||||
|
||||
class Num2Word_ID():
|
||||
|
||||
BASE = {0: [],
|
||||
1: ["satu"],
|
||||
2: ["dua"],
|
||||
3: ["tiga"],
|
||||
4: ["empat"],
|
||||
5: ["lima"],
|
||||
6: ["enam"],
|
||||
7: ["tujuh"],
|
||||
8: ["delapan"],
|
||||
9: ["sembilan"]}
|
||||
|
||||
TENS_TO = {3: "ribu",
|
||||
6: "juta",
|
||||
9: "miliar",
|
||||
12: "triliun",
|
||||
15: "kuadriliun",
|
||||
18: "kuantiliun",
|
||||
21: "sekstiliun",
|
||||
24: "septiliun",
|
||||
27: "oktiliun",
|
||||
30: "noniliun",
|
||||
33: "desiliun"}
|
||||
|
||||
errmsg_floatord = "Cannot treat float number as ordinal"
|
||||
errmsg_negord = "Cannot treat negative number as ordinal"
|
||||
errmsg_toobig = "Too large"
|
||||
max_num = 10**36
|
||||
|
||||
def split_by_koma(self, number):
|
||||
return str(number).split('.')
|
||||
|
||||
def split_by_3(self, number):
|
||||
"""
|
||||
starting here, it groups the number by three from the tail
|
||||
'1234567' -> (('1',),('234',),('567',))
|
||||
:param number:str
|
||||
:rtype:tuple
|
||||
"""
|
||||
blocks = ()
|
||||
length = len(number)
|
||||
|
||||
if length < 3:
|
||||
blocks += ((number,),)
|
||||
else:
|
||||
len_of_first_block = length % 3
|
||||
|
||||
if len_of_first_block > 0:
|
||||
first_block = number[0:len_of_first_block],
|
||||
blocks += first_block,
|
||||
|
||||
for i in range(len_of_first_block, length, 3):
|
||||
next_block = (number[i:i+3],),
|
||||
blocks += next_block
|
||||
|
||||
return blocks
|
||||
|
||||
def spell(self, blocks):
|
||||
"""
|
||||
it adds the list of spelling to the blocks
|
||||
(('1',),('034',)) -> (('1',['satu']),('234',['tiga', 'puluh', 'empat']))
|
||||
:param blocks: tuple
|
||||
:rtype: tuple
|
||||
"""
|
||||
word_blocks = ()
|
||||
first_block = blocks[0]
|
||||
if len(first_block[0]) == 1:
|
||||
if first_block[0] == '0':
|
||||
spelling = ['nol']
|
||||
else:
|
||||
spelling = self.BASE[int(first_block[0])]
|
||||
elif len(first_block[0]) == 2:
|
||||
spelling = self.puluh(first_block[0])
|
||||
else:
|
||||
spelling = self.ratus(first_block[0][0]) + self.puluh(first_block[0][1:3])
|
||||
|
||||
word_blocks += (first_block[0], spelling),
|
||||
|
||||
for block in blocks[1:]:
|
||||
spelling = self.ratus(block[0][0]) + self.puluh(block[0][1:3])
|
||||
block += spelling,
|
||||
word_blocks += block,
|
||||
|
||||
return word_blocks
|
||||
|
||||
def ratus(self, number):
|
||||
# it is used to spell
|
||||
if number == '1':
|
||||
return ['seratus']
|
||||
elif number == '0':
|
||||
return []
|
||||
else:
|
||||
return self.BASE[int(number)]+['ratus']
|
||||
|
||||
def puluh(self, number):
|
||||
# it is used to spell
|
||||
if number[0] == '1':
|
||||
if number[1]== '0':
|
||||
return ['sepuluh']
|
||||
elif number[1] == '1':
|
||||
return ['sebelas']
|
||||
else:
|
||||
return self.BASE[int(number[1])]+['belas']
|
||||
elif number[0] == '0':
|
||||
return self.BASE[int(number[1])]
|
||||
else:
|
||||
return self.BASE[int(number[0])]+['puluh']+ self.BASE[int(number[1])]
|
||||
|
||||
def spell_float(self, float_part):
|
||||
# spell the float number
|
||||
word_list = []
|
||||
for n in float_part:
|
||||
if n == '0':
|
||||
word_list += ['nol']
|
||||
continue
|
||||
word_list += self.BASE[int(n)]
|
||||
return ' '.join(['','koma']+word_list)
|
||||
|
||||
def join(self, word_blocks, float_part):
|
||||
"""
|
||||
join the words by first join lists in the tuple
|
||||
:param word_blocks: tuple
|
||||
:rtype: str
|
||||
"""
|
||||
word_list = []
|
||||
length = len(word_blocks)-1
|
||||
first_block = word_blocks[0],
|
||||
start = 0
|
||||
|
||||
if length == 1 and first_block[0][0] == '1':
|
||||
word_list += ['seribu']
|
||||
start = 1
|
||||
|
||||
for i in range(start, length+1, 1):
|
||||
word_list += word_blocks[i][1]
|
||||
if not word_blocks[i][1]:
|
||||
continue
|
||||
if i == length:
|
||||
break
|
||||
word_list += [self.TENS_TO[(length-i)*3]]
|
||||
|
||||
return ' '.join(word_list)+float_part
|
||||
|
||||
def to_cardinal(self, number):
|
||||
if number >= self.max_num:
|
||||
raise OverflowError(self.errmsg_toobig % (number, self.maxnum))
|
||||
minus = ''
|
||||
if number < 0:
|
||||
minus = 'min '
|
||||
float_word = ''
|
||||
n = self.split_by_koma(abs(number))
|
||||
if len(n)==2:
|
||||
float_word = self.spell_float(n[1])
|
||||
return minus + self.join(self.spell(self.split_by_3(n[0])), float_word)
|
||||
|
||||
def to_ordinal(self, number):
|
||||
self.verify_ordinal(number)
|
||||
out_word = self.to_cardinal(number)
|
||||
if out_word == "satu":
|
||||
return "pertama"
|
||||
return "ke" + out_word
|
||||
|
||||
def to_ordinal_num(self, number):
|
||||
self.verify_ordinal(number)
|
||||
return "ke-" + str(number)
|
||||
|
||||
def to_currency(self, value):
|
||||
return self.to_cardinal(value)+" rupiah"
|
||||
|
||||
def to_year(self, value):
|
||||
return self.to_cardinal(value)
|
||||
|
||||
def verify_ordinal(self, value):
|
||||
if not value == int(value):
|
||||
raise TypeError(self.errmsg_floatord % value)
|
||||
if not abs(value) == value:
|
||||
raise TypeError(self.errmsg_negord % value)
|
||||
217
num2words/lang_IT.py
Normal file
217
num2words/lang_IT.py
Normal file
@@ -0,0 +1,217 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
# MA 02110-1301 USA
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from .lang_EU import Num2Word_EU
|
||||
|
||||
import re
|
||||
import math
|
||||
|
||||
class Num2Word_IT(object):
|
||||
def __init__(self):
|
||||
self._minus = "meno "
|
||||
|
||||
self._exponent = {
|
||||
0 : ('',''),
|
||||
3 : ('mille','mila'),
|
||||
6 : ('milione','miloni'),
|
||||
12 : ('miliardo','miliardi'),
|
||||
18 : ('trillone','trilloni'),
|
||||
24 : ('quadrilione','quadrilioni')}
|
||||
|
||||
self._digits = ['zero', 'uno', 'due', 'tre', 'quattro', 'cinque', 'sei', 'sette', 'otto', 'nove']
|
||||
|
||||
self._sep = ''
|
||||
|
||||
def _toWords(self, num, power=0):
|
||||
str_num = str(num)
|
||||
# The return string;
|
||||
ret = ''
|
||||
|
||||
# add a the word for the minus sign if necessary
|
||||
if num < 0:
|
||||
ret = self._sep + self._minus
|
||||
|
||||
if len(str_num) > 6:
|
||||
current_power = 6
|
||||
# check for highest power
|
||||
if power in self._exponent:
|
||||
# convert the number above the first 6 digits
|
||||
# with it's corresponding $power.
|
||||
snum = str_num[0:-6]
|
||||
if snum != '':
|
||||
ret = ret + self._toWords(int(snum), power + 6)
|
||||
|
||||
num = int(str_num[-6:])
|
||||
if num == 0:
|
||||
return ret
|
||||
|
||||
elif num == 0 or str_num == '':
|
||||
return ' ' + self._digits[0] + ' '
|
||||
else:
|
||||
current_power = len(str_num)
|
||||
|
||||
# See if we need "thousands"
|
||||
thousands = math.floor(num / 1000)
|
||||
if thousands == 1:
|
||||
ret = ret + self._sep + 'mille' + self._sep
|
||||
elif thousands > 1:
|
||||
ret = ret + self._toWords(int(thousands), 3) + self._sep
|
||||
|
||||
# values for digits, tens and hundreds
|
||||
h = int(math.floor((num / 100) % 10))
|
||||
t = int(math.floor((num / 10) % 10))
|
||||
d = int(math.floor(num % 10))
|
||||
|
||||
# centinaia: duecento, trecento, etc...
|
||||
if h == 1:
|
||||
if ((d==0) and (t == 0)):# is it's '100' use 'cien'
|
||||
ret = ret + self._sep + 'cento'
|
||||
else:
|
||||
ret = ret + self._sep + 'cento'
|
||||
elif h == 2 or h == 3 or h == 4 or h == 6 or h == 8:
|
||||
ret = ret + self._sep + self._digits[h] + 'cento'
|
||||
elif h == 5:
|
||||
ret = ret + self._sep + 'cinquecento'
|
||||
elif h == 7:
|
||||
ret = ret + self._sep + 'settecento'
|
||||
elif h == 9:
|
||||
ret = ret + self._sep + 'novecento'
|
||||
|
||||
# decine: venti trenta, etc...
|
||||
if t == 9:
|
||||
if d == 1 or d == 8:
|
||||
ret = ret + self._sep + 'novant'
|
||||
else:
|
||||
ret = ret + self._sep + 'novanta'
|
||||
if t == 8:
|
||||
if d == 1 or d == 8:
|
||||
ret = ret + self._sep + 'ottant'
|
||||
else:
|
||||
ret = ret + self._sep + 'ottanta'
|
||||
if t == 7:
|
||||
if d == 1 or d == 8:
|
||||
ret = ret + self._sep + 'settant'
|
||||
else:
|
||||
ret = ret + self._sep + 'settanta'
|
||||
if t == 6:
|
||||
if d == 1 or d == 8:
|
||||
ret = ret + self._sep + 'sessant'
|
||||
else:
|
||||
ret = ret + self._sep + 'sessanta'
|
||||
if t == 5:
|
||||
if d == 1 or d == 8:
|
||||
ret = ret + self._sep + 'cinquant'
|
||||
else:
|
||||
ret = ret + self._sep + 'cinquanta'
|
||||
if t == 4:
|
||||
if d == 1 or d == 8:
|
||||
ret = ret + self._sep + 'quarant'
|
||||
else:
|
||||
ret = ret + self._sep + 'quaranta'
|
||||
if t == 3:
|
||||
if d == 1 or d == 8:
|
||||
ret = ret + self._sep + 'trent'
|
||||
else:
|
||||
ret = ret + self._sep + 'trenta'
|
||||
if t == 2:
|
||||
if d == 0:
|
||||
ret = ret + self._sep + 'venti'
|
||||
elif (d == 1 or d == 8):
|
||||
ret = ret + self._sep + 'vent' + self._digits[d]
|
||||
else:
|
||||
ret = ret + self._sep + 'venti' + self._digits[d]
|
||||
if t == 1:
|
||||
if d == 0:
|
||||
ret = ret + self._sep + 'dieci'
|
||||
elif d == 1:
|
||||
ret = ret + self._sep + 'undici'
|
||||
elif d == 2:
|
||||
ret = ret + self._sep + 'dodici'
|
||||
elif d == 3:
|
||||
ret = ret + self._sep + 'tredici'
|
||||
elif d == 4:
|
||||
ret = ret + self._sep + 'quattordici'
|
||||
elif d == 5:
|
||||
ret = ret + self._sep + 'quindici'
|
||||
elif d == 6:
|
||||
ret = ret + self._sep + 'sedici'
|
||||
elif d == 7:
|
||||
ret = ret + self._sep + 'diciassette'
|
||||
elif d == 8:
|
||||
ret = ret + self._sep + 'diciotto'
|
||||
elif d == 9:
|
||||
ret = ret + self._sep + 'diciannove'
|
||||
|
||||
# add digits only if it is a multiple of 10 and not 1x or 2x
|
||||
if t != 1 and t != 2 and d > 0:
|
||||
# don't add 'e' for numbers below 10
|
||||
if t != 0:
|
||||
# use 'un' instead of 'uno' when there is a suffix ('mila', 'milloni', etc...)
|
||||
if (power > 0) and ( d == 1):
|
||||
ret = ret + self._sep + 'e un'
|
||||
else:
|
||||
ret = ret + self._sep + '' + self._digits[d]
|
||||
else:
|
||||
if power > 0 and d == 1:
|
||||
ret = ret + self._sep + 'un '
|
||||
else:
|
||||
ret = ret + self._sep + self._digits[d]
|
||||
|
||||
if power > 0:
|
||||
if power in self._exponent:
|
||||
lev = self._exponent[power]
|
||||
|
||||
if lev is None:
|
||||
return None
|
||||
|
||||
# if it's only one use the singular suffix
|
||||
if d == 1 and t == 0 and h == 0:
|
||||
suffix = lev[0]
|
||||
else:
|
||||
suffix = lev[1]
|
||||
|
||||
if num != 0:
|
||||
ret = ret + self._sep + suffix
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def to_cardinal(self, number):
|
||||
return self._toWords(number)
|
||||
|
||||
def to_ordinal_num(self, number):
|
||||
pass
|
||||
|
||||
def to_ordinal(self,value):
|
||||
if 0 <= value <= 10:
|
||||
return ["primo", "secondo", "terzo", "quarto", "quinto", "sesto", "settimo", "ottavo", "nono", "decimo"][value - 1]
|
||||
else:
|
||||
as_word = self._toWords(value)
|
||||
if as_word.endswith("dici"):
|
||||
return re.sub("dici$", "dicesimo", as_word)
|
||||
elif as_word.endswith("to"):
|
||||
return re.sub("to$", "tesimo", as_word)
|
||||
elif as_word.endswith("ta"):
|
||||
return re.sub("ta$", "tesimo", as_word)
|
||||
else:
|
||||
return as_word + "simo"
|
||||
|
||||
|
||||
n2w = Num2Word_IT()
|
||||
to_card = n2w.to_cardinal
|
||||
to_ord = n2w.to_ordinal
|
||||
to_ordnum = n2w.to_ordinal_num
|
||||
|
||||
@@ -85,7 +85,13 @@ vienas litas, nulis centų
|
||||
vienas tūkstantis du šimtai trisdešimt keturi litai, penkiasdešimt šeši centai
|
||||
|
||||
>>> print(to_currency(-1251985, cents = False))
|
||||
minus dvylika tūkstančių penki šimtai devyniolika litų, 85 centai
|
||||
minus dvylika tūkstančių penki šimtai devyniolika eurų, 85 centai
|
||||
|
||||
>>> print(to_currency(1.0, 'EUR'))
|
||||
vienas euras, nulis centų
|
||||
|
||||
>>> print(to_currency(1234.56, 'EUR'))
|
||||
vienas tūkstantis du šimtai trisdešimt keturi eurai, penkiasdešimt šeši centai
|
||||
"""
|
||||
from __future__ import unicode_literals
|
||||
|
||||
@@ -144,6 +150,7 @@ THOUSANDS = {
|
||||
|
||||
CURRENCIES = {
|
||||
'LTL': ((u'litas', u'litai', u'litų'), (u'centas', u'centai', u'centų')),
|
||||
'EUR': ((u'euras', u'eurai', u'eurų'), (u'centas', u'centai', u'centų')),
|
||||
}
|
||||
|
||||
def splitby3(n):
|
||||
@@ -210,7 +217,7 @@ def n2w(n):
|
||||
else:
|
||||
return int2word(int(n))
|
||||
|
||||
def to_currency(n, currency='LTL', cents = True):
|
||||
def to_currency(n, currency='EUR', cents = True):
|
||||
if type(n) == int:
|
||||
if n < 0:
|
||||
minus = True
|
||||
|
||||
123
num2words/lang_NO.py
Normal file
123
num2words/lang_NO.py
Normal file
@@ -0,0 +1,123 @@
|
||||
# Copyright (c) 2003, Taro Ogawa. All Rights Reserved.
|
||||
# Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved.
|
||||
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
# MA 02110-1301 USA
|
||||
|
||||
from __future__ import division, unicode_literals, print_function
|
||||
from . import lang_EU
|
||||
|
||||
class Num2Word_NO(lang_EU.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 + "illard"
|
||||
self.cards[10**(n-3)] = word + "illion"
|
||||
|
||||
def setup(self):
|
||||
self.negword = "minus "
|
||||
self.pointword = "komma"
|
||||
self.errmsg_nornum = "Bare tall kan bli konvertert til ord."
|
||||
self.exclude_title = ["og", "komma", "minus"]
|
||||
|
||||
self.mid_numwords = [(1000, "tusen"), (100, "hundre"),
|
||||
(90, "nitti"), (80, "\xe5tti"), (70, "sytti"),
|
||||
(60, "seksti"), (50, "femti"), (40, "f\xf8rti"),
|
||||
(30, "tretti")]
|
||||
self.low_numwords = ["tjue", "nitten", "atten", "sytten",
|
||||
"seksten", "femten", "fjorten", "tretten",
|
||||
"tolv", "elleve", "ti", "ni", "\xe5tte",
|
||||
"syv", "seks", "fem", "fire", "tre", "to",
|
||||
"en", "null"]
|
||||
self.ords = { "en" : "f\xf8rste",
|
||||
"to" : "andre",
|
||||
"tre" : "tredje",
|
||||
"fire" : "fjerde",
|
||||
"fem" : "femte",
|
||||
"seks" : "sjette",
|
||||
"syv" : "syvende",
|
||||
"\xe5tte" : "\xe5ttende",
|
||||
"ni" : "niende",
|
||||
"ti" : "tiende",
|
||||
"elleve" : "ellevte",
|
||||
"tolv" : "tolvte",
|
||||
"tjue" : "tjuende" }
|
||||
|
||||
|
||||
def merge(self, lpair, rpair):
|
||||
ltext, lnum = lpair
|
||||
rtext, rnum = rpair
|
||||
if lnum == 1 and rnum < 100:
|
||||
return (rtext, rnum)
|
||||
elif 100 > lnum > rnum :
|
||||
return ("%s-%s"%(ltext, rtext), lnum + rnum)
|
||||
elif lnum >= 100 > rnum:
|
||||
return ("%s og %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[-2:] == "ti":
|
||||
lastword = lastword + "ende"
|
||||
else:
|
||||
lastword += "de"
|
||||
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="hundre", jointxt="og",
|
||||
longval=longval)
|
||||
|
||||
def to_currency(self, val, longval=True):
|
||||
return self.to_splitnum(val, hightxt="krone/r", lowtxt="\xf8re/r",
|
||||
jointxt="og", longval=longval, cents = True)
|
||||
|
||||
|
||||
n2w = Num2Word_NO()
|
||||
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, "er", n2w.to_currency(val))
|
||||
print(val, "er", n2w.to_year(val))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
209
num2words/lang_PT_BR.py
Normal file
209
num2words/lang_PT_BR.py
Normal file
@@ -0,0 +1,209 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2003, Taro Ogawa. All Rights Reserved.
|
||||
# Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved.
|
||||
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
# MA 02110-1301 USA
|
||||
|
||||
from __future__ import division, unicode_literals
|
||||
import re
|
||||
|
||||
from . import lang_EU
|
||||
|
||||
|
||||
class Num2Word_PT_BR(lang_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 + "ilhão"
|
||||
|
||||
def setup(self):
|
||||
self.negword = "menos "
|
||||
self.pointword = "vírgula"
|
||||
self.errmsg_nornum = "Somente números podem ser convertidos para palavras"
|
||||
self.exclude_title = ["e", "vírgula", "menos"]
|
||||
|
||||
self.mid_numwords = [
|
||||
(1000, "mil"), (100, "cem"), (90, "noventa"),
|
||||
(80, "oitenta"), (70, "setenta"), (60, "sessenta"), (50, "cinquenta"),
|
||||
(40, "quarenta"), (30, "trinta")
|
||||
]
|
||||
self.low_numwords = [
|
||||
"vinte", "dezenove", "dezoito", "dezessete", "dezesseis",
|
||||
"quinze", "catorze", "treze", "doze", "onze", "dez",
|
||||
"nove", "oito", "sete", "seis", "cinco", "quatro", "três", "dois",
|
||||
"um", "zero"
|
||||
]
|
||||
self.ords = [
|
||||
{
|
||||
0: "",
|
||||
1: "primeiro",
|
||||
2: "segundo",
|
||||
3: "terceiro",
|
||||
4: "quarto",
|
||||
5: "quinto",
|
||||
6: "sexto",
|
||||
7: "sétimo",
|
||||
8: "oitavo",
|
||||
9: "nono",
|
||||
},
|
||||
{
|
||||
0: "",
|
||||
1: "décimo",
|
||||
2: "vigésimo",
|
||||
3: "trigésimo",
|
||||
4: "quadragésimo",
|
||||
5: "quinquagésimo",
|
||||
6: "sexagésimo",
|
||||
7: "septuagésimo",
|
||||
8: "octogésimo",
|
||||
9: "nonagésimo",
|
||||
},
|
||||
{
|
||||
0: "",
|
||||
1: "centésimo",
|
||||
2: "ducentésimo",
|
||||
3: "tricentésimo",
|
||||
4: "quadrigentésimo",
|
||||
5: "quingentésimo",
|
||||
6: "seiscentésimo",
|
||||
7: "septigentésimo",
|
||||
8: "octigentésimo",
|
||||
9: "nongentésimo",
|
||||
},
|
||||
]
|
||||
self.thousand_separators = {
|
||||
3: "milésimo",
|
||||
6: "milionésimo",
|
||||
9: "bilionésimo",
|
||||
12: "trilionésimo",
|
||||
15: "quadrilionésimo"
|
||||
}
|
||||
self.hundreds = {
|
||||
1: "cento",
|
||||
2: "duzentos",
|
||||
3: "trezentos",
|
||||
4: "quatrocentos",
|
||||
5: "quinhentos",
|
||||
6: "seiscentos",
|
||||
7: "setecentos",
|
||||
8: "oitocentos",
|
||||
9: "novecentos",
|
||||
}
|
||||
|
||||
def merge(self, curr, next):
|
||||
ctext, cnum, ntext, nnum = curr + next
|
||||
|
||||
if cnum == 1:
|
||||
if nnum < 1000000:
|
||||
return next
|
||||
ctext = "um"
|
||||
elif cnum == 100 and not nnum == 1000:
|
||||
ctext = "cento"
|
||||
|
||||
if nnum < cnum:
|
||||
if cnum < 100:
|
||||
return ("%s e %s" % (ctext, ntext), cnum + nnum)
|
||||
return ("%s e %s" % (ctext, ntext), cnum + nnum)
|
||||
|
||||
elif (not nnum % 1000000) and cnum > 1:
|
||||
ntext = ntext[:-4] + "lhões"
|
||||
|
||||
if nnum == 100:
|
||||
ctext = self.hundreds[cnum]
|
||||
ntext = ""
|
||||
|
||||
else:
|
||||
ntext = " " + ntext
|
||||
|
||||
return (ctext + ntext, cnum * nnum)
|
||||
|
||||
def to_cardinal(self, value):
|
||||
result = super(Num2Word_PT_BR, self).to_cardinal(value)
|
||||
|
||||
# Transforms "mil E cento e catorze reais" into "mil, cento e catorze reais"
|
||||
for ext in (
|
||||
'mil', 'milhão', 'milhões', 'bilhão', 'bilhões',
|
||||
'trilhão', 'trilhões', 'quatrilhão', 'quatrilhões'):
|
||||
if re.match('.*{} e \w*ento'.format(ext), result):
|
||||
result = result.replace('{} e'.format(ext), '{},'.format(ext), 1)
|
||||
|
||||
return result
|
||||
|
||||
def to_ordinal(self, value):
|
||||
self.verify_ordinal(value)
|
||||
|
||||
result = []
|
||||
value = str(value)
|
||||
thousand_separator = ''
|
||||
|
||||
for idx, char in enumerate(value[::-1]):
|
||||
if idx and idx % 3 == 0:
|
||||
thousand_separator = self.thousand_separators[idx]
|
||||
|
||||
if char != '0' and thousand_separator:
|
||||
# avoiding "segundo milionésimo milésimo" for 6000000, for instance
|
||||
result.append(thousand_separator)
|
||||
thousand_separator = ''
|
||||
|
||||
result.append(self.ords[idx % 3][int(char)])
|
||||
|
||||
result = ' '.join(result[::-1])
|
||||
result = result.strip()
|
||||
result = re.sub('\s+', ' ', result)
|
||||
|
||||
if result.startswith('primeiro') and value != '1':
|
||||
# avoiding "primeiro milésimo", "primeiro milionésimo" and so on
|
||||
result = result[9:]
|
||||
|
||||
return result
|
||||
|
||||
def to_ordinal_num(self, value):
|
||||
self.verify_ordinal(value)
|
||||
return "%sº" % (value)
|
||||
|
||||
def to_year(self, val, longval=True):
|
||||
if val < 0:
|
||||
return self.to_cardinal(abs(val)) + ' antes de Cristo'
|
||||
return self.to_cardinal(val)
|
||||
|
||||
def to_currency(self, val, longval=True):
|
||||
integer_part, decimal_part = ('%.2f' % val).split('.')
|
||||
|
||||
result = self.to_cardinal(int(integer_part))
|
||||
|
||||
appended_currency = False
|
||||
for ext in (
|
||||
'milhão', 'milhões', 'bilhão', 'bilhões',
|
||||
'trilhão', 'trilhões', 'quatrilhão', 'quatrilhões'):
|
||||
if result.endswith(ext):
|
||||
result += ' de reais'
|
||||
appended_currency = True
|
||||
|
||||
if result in ['um', 'menos um']:
|
||||
result += ' real'
|
||||
appended_currency = True
|
||||
if not appended_currency:
|
||||
result += ' reais'
|
||||
|
||||
if int(decimal_part):
|
||||
cents = self.to_cardinal(int(decimal_part))
|
||||
result += ' e ' + cents
|
||||
|
||||
if cents == 'um':
|
||||
result += ' centavo'
|
||||
else:
|
||||
result += ' centavos'
|
||||
|
||||
return result
|
||||
312
num2words/lang_RU.py
Normal file
312
num2words/lang_RU.py
Normal file
@@ -0,0 +1,312 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Copyright (c) 2003, Taro Ogawa. All Rights Reserved.
|
||||
# Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved.
|
||||
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
# MA 02110-1301 USA
|
||||
u"""
|
||||
>>> from textwrap import fill
|
||||
|
||||
>>> ' '.join([str(i) for i in splitby3('1')])
|
||||
u'1'
|
||||
>>> ' '.join([str(i) for i in splitby3('1123')])
|
||||
u'1 123'
|
||||
>>> ' '.join([str(i) for i in splitby3('1234567890')])
|
||||
u'1 234 567 890'
|
||||
|
||||
>>> print(' '.join([n2w(i) for i in range(10)]))
|
||||
ноль один два три четыре пять шесть семь восемь девять
|
||||
|
||||
>>> print(fill(' '.join([n2w(i+10) for i in range(10)])))
|
||||
десять одиннадцать двенадцать тринадцать четырнадцать пятнадцать
|
||||
шестнадцать семнадцать восемнадцать девятнадцать
|
||||
|
||||
>>> print(fill(' '.join([n2w(i*10) for i in range(10)])))
|
||||
ноль десять двадцать тридцать сорок пятьдесят шестьдесят семьдесят
|
||||
восемьдесят девяносто
|
||||
|
||||
>>> print(n2w(100))
|
||||
сто
|
||||
>>> print(n2w(101))
|
||||
сто один
|
||||
>>> print(n2w(110))
|
||||
сто десять
|
||||
>>> print(n2w(115))
|
||||
сто пятнадцать
|
||||
>>> print(n2w(123))
|
||||
сто двадцать три
|
||||
>>> print(n2w(1000))
|
||||
тысяча
|
||||
>>> print(n2w(1001))
|
||||
тысяча один
|
||||
>>> print(n2w(2012))
|
||||
две тысячи двенадцать
|
||||
|
||||
>>> print(n2w(12519.85))
|
||||
двенадцать тысяч пятьсот девятнадцать запятая восемьдесят пять
|
||||
|
||||
>>> print(fill(n2w(1234567890)))
|
||||
миллиард двести тридцать четыре миллиона пятьсот шестьдесят семь тысяч
|
||||
восемьсот девяносто
|
||||
|
||||
>>> print(fill(n2w(215461407892039002157189883901676)))
|
||||
двести пятнадцать нониллионов четыреста шестьдесят один октиллион
|
||||
четыреста семь септиллионов восемьсот девяносто два секстиллиона
|
||||
тридцать девять квинтиллионов два квадриллиона сто пятьдесят семь
|
||||
триллионов сто восемьдесят девять миллиардов восемьсот восемьдесят три
|
||||
миллиона девятьсот одна тысяча шестьсот семьдесят шесть
|
||||
|
||||
>>> print(fill(n2w(719094234693663034822824384220291)))
|
||||
семьсот девятнадцать нониллионов девяносто четыре октиллиона двести
|
||||
тридцать четыре септиллиона шестьсот девяносто три секстиллиона
|
||||
шестьсот шестьдесят три квинтиллиона тридцать четыре квадриллиона
|
||||
восемьсот двадцать два триллиона восемьсот двадцать четыре миллиарда
|
||||
триста восемьдесят четыре миллиона двести двадцать тысяч двести
|
||||
девяносто один
|
||||
|
||||
>>> print(to_currency(1.0, 'EUR'))
|
||||
один евро, ноль центов
|
||||
|
||||
>>> print(to_currency(1.0, 'RUB'))
|
||||
один рубль, ноль копеек
|
||||
|
||||
>>> print(to_currency(1234.56, 'EUR'))
|
||||
тысяча двести тридцать четыре евро, пятьдесят шесть центов
|
||||
|
||||
>>> print(to_currency(1234.56, 'RUB'))
|
||||
тысяча двести тридцать четыре рубля, пятьдесят шесть копеек
|
||||
|
||||
>>> print(to_currency(10111, 'EUR', seperator=u' и'))
|
||||
сто один евро и одиннадцать центов
|
||||
|
||||
>>> print(to_currency(10121, 'RUB', seperator=u' и'))
|
||||
сто один рубль и двадцать одна копейка
|
||||
|
||||
>>> print(to_currency(10122, 'RUB', seperator=u' и'))
|
||||
сто один рубль и двадцать две копейки
|
||||
|
||||
>>> print(to_currency(10121, 'EUR', seperator=u' и'))
|
||||
сто один евро и двадцать один цент
|
||||
|
||||
>>> print(to_currency(-1251985, cents = False))
|
||||
минус двенадцать тысяч пятьсот девятнадцать евро, 85 центов
|
||||
"""
|
||||
from __future__ import unicode_literals
|
||||
|
||||
ZERO = (u'ноль',)
|
||||
|
||||
ONES_FEMININE = {
|
||||
1: (u'одна',),
|
||||
2: (u'две',),
|
||||
3: (u'три',),
|
||||
4: (u'четыре',),
|
||||
5: (u'пять',),
|
||||
6: (u'шесть',),
|
||||
7: (u'семь',),
|
||||
8: (u'восемь',),
|
||||
9: (u'девять',),
|
||||
}
|
||||
|
||||
ONES = {
|
||||
1: (u'один',),
|
||||
2: (u'два',),
|
||||
3: (u'три',),
|
||||
4: (u'четыре',),
|
||||
5: (u'пять',),
|
||||
6: (u'шесть',),
|
||||
7: (u'семь',),
|
||||
8: (u'восемь',),
|
||||
9: (u'девять',),
|
||||
}
|
||||
|
||||
TENS = {
|
||||
0: (u'десять',),
|
||||
1: (u'одиннадцать',),
|
||||
2: (u'двенадцать',),
|
||||
3: (u'тринадцать',),
|
||||
4: (u'четырнадцать',),
|
||||
5: (u'пятнадцать',),
|
||||
6: (u'шестнадцать',),
|
||||
7: (u'семнадцать',),
|
||||
8: (u'восемнадцать',),
|
||||
9: (u'девятнадцать',),
|
||||
}
|
||||
|
||||
TWENTIES = {
|
||||
2: (u'двадцать',),
|
||||
3: (u'тридцать',),
|
||||
4: (u'сорок',),
|
||||
5: (u'пятьдесят',),
|
||||
6: (u'шестьдесят',),
|
||||
7: (u'семьдесят',),
|
||||
8: (u'восемьдесят',),
|
||||
9: (u'девяносто',),
|
||||
}
|
||||
|
||||
HUNDREDS = {
|
||||
1: (u'сто',),
|
||||
2: (u'двести',),
|
||||
3: (u'триста',),
|
||||
4: (u'четыреста',),
|
||||
5: (u'пятьсот',),
|
||||
6: (u'шестьсот',),
|
||||
7: (u'семьсот',),
|
||||
8: (u'восемьсот',),
|
||||
9: (u'девятьсот',),
|
||||
}
|
||||
|
||||
THOUSANDS = {
|
||||
1: (u'тысяча', u'тысячи', u'тысяч'), # 10^3
|
||||
2: (u'миллион', u'миллиона', u'миллионов'), # 10^6
|
||||
3: (u'миллиард', u'миллиарда', u'миллиардов'), # 10^9
|
||||
4: (u'триллион', u'триллиона', u'триллионов'), # 10^12
|
||||
5: (u'квадриллион', u'квадриллиона', u'квадриллионов'), # 10^15
|
||||
6: (u'квинтиллион', u'квинтиллиона', u'квинтиллионов'), # 10^18
|
||||
7: (u'секстиллион', u'секстиллиона', u'секстиллионов'), # 10^21
|
||||
8: (u'септиллион', u'септиллиона', u'септиллионов'), # 10^24
|
||||
9: (u'октиллион', u'октиллиона', u'октиллионов'), #10^27
|
||||
10: (u'нониллион', u'нониллиона', u'нониллионов'), # 10^30
|
||||
}
|
||||
|
||||
CURRENCIES = {
|
||||
'RUB': (
|
||||
(u'рубль', u'рубля', u'рублей'), (u'копейка', u'копейки', u'копеек')
|
||||
),
|
||||
'EUR': (
|
||||
(u'евро', u'евро', u'евро'), (u'цент', u'цента', u'центов')
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
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):
|
||||
if (n % 100 < 10 or n % 100 > 20):
|
||||
if n % 10 == 1:
|
||||
form = 0
|
||||
elif (n % 10 > 1 and n % 10 < 5):
|
||||
form = 1
|
||||
else:
|
||||
form = 2
|
||||
else:
|
||||
form = 2
|
||||
return forms[form]
|
||||
|
||||
|
||||
def int2word(n, feminine=False):
|
||||
if n < 0:
|
||||
return ' '.join([u'минус', int2word(abs(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:
|
||||
words.append(HUNDREDS[n3][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):
|
||||
ones = ONES_FEMININE if i == 1 or feminine and i == 0 else ONES
|
||||
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 запятая %s' % (int2word(int(left)), int2word(int(right)))
|
||||
else:
|
||||
return int2word(int(n))
|
||||
|
||||
|
||||
def to_currency(n, currency='EUR', cents=True, seperator=','):
|
||||
if type(n) == int:
|
||||
if n < 0:
|
||||
minus = True
|
||||
else:
|
||||
minus = False
|
||||
|
||||
n = abs(n)
|
||||
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)
|
||||
minus = False
|
||||
cr1, cr2 = CURRENCIES[currency]
|
||||
|
||||
if minus:
|
||||
minus_str = "минус "
|
||||
else:
|
||||
minus_str = ""
|
||||
|
||||
if cents:
|
||||
cents_feminine = currency == 'RUB'
|
||||
cents_str = int2word(right, cents_feminine)
|
||||
else:
|
||||
cents_str = "%02d" % right
|
||||
|
||||
return u'%s%s %s%s %s %s' % (
|
||||
minus_str,
|
||||
int2word(left),
|
||||
pluralize(left, cr1),
|
||||
seperator,
|
||||
cents_str,
|
||||
pluralize(right, cr2)
|
||||
)
|
||||
|
||||
|
||||
class Num2Word_RU(object):
|
||||
def to_cardinal(self, number):
|
||||
return n2w(number)
|
||||
|
||||
def to_ordinal(self, number):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
Reference in New Issue
Block a user