diff --git a/num2words/__init__.py b/num2words/__init__.py index 04da9c2..f117a78 100644 --- a/num2words/__init__.py +++ b/num2words/__init__.py @@ -18,7 +18,6 @@ from __future__ import unicode_literals from . import lang_AR from . import lang_EN -from . import lang_EN_GB from . import lang_EN_IN from . import lang_FR from . import lang_FR_CH @@ -46,7 +45,6 @@ from . import lang_SL CONVERTER_CLASSES = { 'ar': lang_AR.Num2Word_AR(), '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(), diff --git a/num2words/base.py b/num2words/base.py index 5b3657f..a312f32 100644 --- a/num2words/base.py +++ b/num2words/base.py @@ -21,9 +21,13 @@ from collections import OrderedDict from decimal import Decimal from .compat import to_s +from .currency import parse_currency_parts, prefix_currency class Num2Word_Base(object): + CURRENCY_FORMS = {} + CURRENCY_ADJECTIVES = {} + def __init__(self): self.cards = OrderedDict() self.is_title = False @@ -243,8 +247,54 @@ class Num2Word_Base(object): def to_year(self, value, **kwargs): return self.to_cardinal(value) - def to_currency(self, value, **kwargs): - return self.to_cardinal(value) + def pluralize(self, n, forms): + """ + Should resolve gettext form: + http://docs.translatehouse.org/projects/localization-guide/en/latest/l10n/pluralforms.html + """ + raise NotImplementedError + + def _cents_verbose(self, number, currency): + return self.to_cardinal(number) + + def to_currency(self, val, currency='EUR', cents=True, seperator=',', + adjective=False): + """ + Args: + val: Numeric value + currency (str): Currency code + cents (bool): Verbose cents + seperator (str): Cent seperator + adjective (bool): Prefix currency name with adjective + Returns: + str: Formatted string + + """ + left, right, is_negative = parse_currency_parts(val) + + try: + cr1, cr2 = self.CURRENCY_FORMS[currency] + + except KeyError: + raise NotImplementedError( + 'Currency code "%s" not implemented for "%s"' % + (currency, self.__class__.__name__)) + + if adjective and currency in self.CURRENCY_ADJECTIVES: + cr1 = prefix_currency(self.CURRENCY_ADJECTIVES[currency], cr1) + + minus_str = "%s " % self.negword if is_negative else "" + cents_str = self._cents_verbose(right, currency) \ + if cents else "%02d" % right + + return u'%s%s %s%s %s %s' % ( + minus_str, + self.to_cardinal(left), + self.pluralize(left, cr1), + seperator, + cents_str, + self.pluralize(right, cr2) + ) def base_setup(self): pass diff --git a/num2words/lang_EN.py b/num2words/lang_EN.py index fd6fc58..4c4fb07 100644 --- a/num2words/lang_EN.py +++ b/num2words/lang_EN.py @@ -26,6 +26,8 @@ class Num2Word_EN(lang_EU.Num2Word_EU): self.cards[10 ** n] = word + "illion" def setup(self): + super(Num2Word_EN, self).setup() + self.negword = "minus " self.pointword = "point" self.errmsg_nornum = "Only numbers may be converted to words." @@ -85,33 +87,3 @@ class Num2Word_EN(lang_EU.Num2Word_EU): return self.to_cardinal(val) return self.to_splitnum(val, hightxt="hundred", jointxt="and", longval=longval) - - def to_currency(self, val, longval=True, **kwargs): - if 'currency' in kwargs: - return self._to_currency(val, **kwargs) - - return self.to_splitnum(val, hightxt="dollar/s", lowtxt="cent/s", - jointxt="and", longval=longval, cents=True) - - -n2w = Num2Word_EN() -to_card = n2w.to_cardinal -to_ord = n2w.to_ordinal -to_ordnum = n2w.to_ordinal_num -to_year = n2w.to_year - - -def main(): - for val in [1, 11, 12, 21, 31, 33, 71, 80, 81, 91, 99, 100, 101, 102, 155, - 180, 300, 308, 832, 1000, 1001, 1061, 1100, 1500, 1701, 3000, - 8280, 8291, 150000, 500000, 1000000, 2000000, 2000001, - -21212121211221211111, -2.121212, -1.0000100]: - n2w.test(val) - n2w.test(13253254360678768017687001076010010122121321432104732075403270573) - for val in [1, 120, 1000, 1120, 1800, 1976, 2000, 2010, 2099, 2171]: - print(val, "is", n2w.to_currency(val)) - print(val, "is", n2w.to_year(val)) - - -if __name__ == "__main__": - main() diff --git a/num2words/lang_EN_EUR.py b/num2words/lang_EN_EUR.py deleted file mode 100644 index 04db601..0000000 --- a/num2words/lang_EN_EUR.py +++ /dev/null @@ -1,53 +0,0 @@ -# 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 print_function, unicode_literals - -from .lang_EN import Num2Word_EN - - -class Num2Word_EN_EUR(Num2Word_EN): - def to_currency(self, val, longval=True, cents=True, jointxt="and", - **kwargs): - if 'currency' in kwargs: - return self._to_currency(val, **kwargs) - - return self.to_splitnum(val, hightxt="euro/s", lowtxt="cents", - jointxt=jointxt, longval=longval, cents=cents) - - -n2w = Num2Word_EN_EUR() -to_card = n2w.to_cardinal -to_ord = n2w.to_ordinal -to_ordnum = n2w.to_ordinal_num -to_year = n2w.to_year -to_currency = n2w.to_currency - - -def main(): - for val in [1, 11, 12, 21, 31, 33, 71, 80, 81, 91, 99, 100, 101, 102, 155, - 180, 300, 308, 832, 1000, 1001, 1061, 1100, 1500, 1701, 3000, - 8280, 8291, 150000, 500000, 1000000, 2000000, 2000001, - -21212121211221211111, -2.121212, -1.0000100]: - n2w.test(val) - n2w.test(13253254360678768017687001076010010122121321432104732075403270573) - for val in [1, 120, 1000, 1120, 1800, 1976, 2000, 2010, 2099, 2171]: - print(val, "is", n2w.to_currency(val)) - print(val, "is", n2w.to_year(val)) - - -if __name__ == "__main__": - main() diff --git a/num2words/lang_EN_GB.py b/num2words/lang_EN_GB.py deleted file mode 100644 index 59a7cfc..0000000 --- a/num2words/lang_EN_GB.py +++ /dev/null @@ -1,51 +0,0 @@ -# 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 print_function, unicode_literals - -from .lang_EN import Num2Word_EN - - -class Num2Word_EN_GB(Num2Word_EN): - def to_currency(self, val, longval=True, **kwargs): - if 'currency' in kwargs: - return self._to_currency(val, **kwargs) - - return self.to_splitnum(val, hightxt="pound/s", lowtxt="pence", - jointxt="and", longval=longval) - - -n2w = Num2Word_EN_GB() -to_card = n2w.to_cardinal -to_ord = n2w.to_ordinal -to_ordnum = n2w.to_ordinal_num -to_year = n2w.to_year - - -def main(): - for val in [1, 11, 12, 21, 31, 33, 71, 80, 81, 91, 99, 100, 101, 102, 155, - 180, 300, 308, 832, 1000, 1001, 1061, 1100, 1500, 1701, 3000, - 8280, 8291, 150000, 500000, 1000000, 2000000, 2000001, - -21212121211221211111, -2.121212, -1.0000100]: - n2w.test(val) - n2w.test(13253254360678768017687001076010010122121321432104732075403270573) - for val in [1, 120, 1000, 1120, 1800, 1976, 2000, 2010, 2099, 2171]: - print(val, "is", n2w.to_currency(val)) - print(val, "is", n2w.to_year(val)) - - -if __name__ == "__main__": - main() diff --git a/num2words/lang_EU.py b/num2words/lang_EU.py index 85a9a1a..ddfee92 100644 --- a/num2words/lang_EU.py +++ b/num2words/lang_EU.py @@ -18,48 +18,39 @@ from __future__ import unicode_literals from .base import Num2Word_Base -from .currency import parse_currency_parts, prefix_currency GENERIC_DOLLARS = ('dollar', 'dollars') GENERIC_CENTS = ('cent', 'cents') -""" -Source: http://publications.europa.eu/code/en/en-5000500.htm -""" -CURRENCIES = { - 'AUD': (GENERIC_DOLLARS, GENERIC_CENTS), - 'CAD': (GENERIC_DOLLARS, GENERIC_CENTS), - # repalced by EUR - 'EEK': (('kroon', 'kroons'), ('sent', 'senti')), - 'EUR': (('euro', 'euro'), GENERIC_CENTS), - 'GBP': (('pound sterling', 'pounds sterling'), ('penny', 'pence')), - # replaced by EUR - 'LTL': ('litas', 'litas', GENERIC_CENTS), - # replaced by EUR - 'LVL': (('lat', 'lats'), ('santim', 'santims')), - 'USD': (GENERIC_DOLLARS, GENERIC_CENTS), - 'RUB': (('rouble', 'roubles'), ('kopek', 'kopeks')), - 'SEK': (('krona', 'kronor'), ('öre', 'öre')), - 'NOK': (('krone', 'kroner'), ('øre', 'øre')), - 'PLN': (('zloty', 'zlotys', 'zlotu'), ('grosz', 'groszy')), -} - -PREFIXES = { - 'AUD': 'Australian', - 'CAD': 'Canadian', - 'EEK': 'Estonian', - 'USD': 'US', - 'RUB': 'Russian', - 'NOK': 'Norwegian', -} - - -def pluralize(n, forms): - form = 0 if n == 1 else 1 - return forms[form] - class Num2Word_EU(Num2Word_Base): + CURRENCY_FORMS = { + 'AUD': (GENERIC_DOLLARS, GENERIC_CENTS), + 'CAD': (GENERIC_DOLLARS, GENERIC_CENTS), + # repalced by EUR + 'EEK': (('kroon', 'kroons'), ('sent', 'senti')), + 'EUR': (('euro', 'euro'), GENERIC_CENTS), + 'GBP': (('pound sterling', 'pounds sterling'), ('penny', 'pence')), + # replaced by EUR + 'LTL': (('litas', 'litas'), GENERIC_CENTS), + # replaced by EUR + 'LVL': (('lat', 'lats'), ('santim', 'santims')), + 'USD': (GENERIC_DOLLARS, GENERIC_CENTS), + 'RUB': (('rouble', 'roubles'), ('kopek', 'kopeks')), + 'SEK': (('krona', 'kronor'), ('öre', 'öre')), + 'NOK': (('krone', 'kroner'), ('øre', 'øre')), + 'PLN': (('zloty', 'zlotys', 'zlotu'), ('grosz', 'groszy')), + } + + CURRENCY_ADJECTIVES = { + 'AUD': 'Australian', + 'CAD': 'Canadian', + 'EEK': 'Estonian', + 'USD': 'US', + 'RUB': 'Russian', + 'NOK': 'Norwegian', + } + def set_high_numwords(self, high): max = 3 + 6 * len(high) @@ -67,6 +58,10 @@ class Num2Word_EU(Num2Word_Base): self.cards[10 ** n] = word + "illiard" self.cards[10 ** (n - 3)] = word + "illion" + def pluralize(self, n, forms): + form = 0 if n == 1 else 1 + return forms[form] + def base_setup(self): lows = ["non", "oct", "sept", "sext", "quint", "quadr", "tr", "b", "m"] units = ["", "un", "duo", "tre", "quattuor", "quin", "sex", "sept", @@ -75,30 +70,3 @@ class Num2Word_EU(Num2Word_Base): "sexagint", "septuagint", "octogint", "nonagint"] self.high_numwords = ["cent"] + self.gen_high_numwords(units, tens, lows) - - def to_currency(self, val, longval=True, jointxt="", **kwargs): - if 'currency' in kwargs: - return self._to_currency(val, **kwargs) - - return self.to_splitnum(val, hightxt="Euro/s", lowtxt="Euro cent/s", - jointxt=jointxt, longval=longval) - - def _to_currency(self, val, currency='EUR', cents=True, seperator=',', - prefix=False): - left, right, is_negative = parse_currency_parts(val) - cr1, cr2 = CURRENCIES[currency] - - if prefix and currency in PREFIXES: - cr1 = prefix_currency(PREFIXES[currency], cr1) - - minus_str = "minus " if is_negative else "" - cents_str = self.to_cardinal(right) if cents else "%02d" % right - - return u'%s%s %s%s %s %s' % ( - minus_str, - self.to_cardinal(left), - pluralize(left, cr1), - seperator, - cents_str, - pluralize(right, cr2) - ) diff --git a/num2words/lang_HE.py b/num2words/lang_HE.py index 15378a3..31dbdaf 100644 --- a/num2words/lang_HE.py +++ b/num2words/lang_HE.py @@ -18,6 +18,8 @@ from __future__ import print_function, unicode_literals +from .utils import get_digits, splitby3 + ZERO = (u'אפס',) ONES = { @@ -70,22 +72,6 @@ THOUSANDS = { 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) diff --git a/num2words/lang_LT.py b/num2words/lang_LT.py index 326c6c7..d157509 100644 --- a/num2words/lang_LT.py +++ b/num2words/lang_LT.py @@ -14,237 +14,131 @@ # 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 - ->>> print(' '.join([str(i) for i in splitby3('1')])) -1 ->>> print(' '.join([str(i) for i in splitby3('1123')])) -1 123 ->>> print(' '.join([str(i) for i in splitby3('1234567890')])) -1 234 567 890 - ->>> print(' '.join([n2w(i) for i in range(10)])) -nulis vienas du trys keturi penki šeši septyni aštuoni devyni - ->>> print(fill(' '.join([n2w(i+10) for i in range(10)]))) -dešimt vienuolika dvylika trylika keturiolika penkiolika šešiolika -septyniolika aštuoniolika devyniolika - ->>> print(fill(' '.join([n2w(i*10) for i in range(10)]))) -nulis dešimt dvidešimt trisdešimt keturiasdešimt penkiasdešimt -šešiasdešimt septyniasdešimt aštuoniasdešimt devyniasdešimt - ->>> print(n2w(100)) -vienas šimtas ->>> print(n2w(101)) -vienas šimtas vienas ->>> print(n2w(110)) -vienas šimtas dešimt ->>> print(n2w(115)) -vienas šimtas penkiolika ->>> print(n2w(123)) -vienas šimtas dvidešimt trys ->>> print(n2w(1000)) -vienas tūkstantis ->>> print(n2w(1001)) -vienas tūkstantis vienas ->>> print(n2w(2012)) -du tūkstančiai dvylika - ->>> print(fill(n2w(1234567890))) -vienas milijardas du šimtai trisdešimt keturi milijonai penki šimtai -šešiasdešimt septyni tūkstančiai aštuoni šimtai devyniasdešimt - ->>> print(fill(n2w(215461407892039002157189883901676))) -du šimtai penkiolika naintilijonų keturi šimtai šešiasdešimt vienas -oktilijonas keturi šimtai septyni septilijonai aštuoni šimtai -devyniasdešimt du sikstilijonai trisdešimt devyni kvintilijonai du -kvadrilijonai vienas šimtas penkiasdešimt septyni trilijonai vienas -šimtas aštuoniasdešimt devyni milijardai aštuoni šimtai -aštuoniasdešimt trys milijonai devyni šimtai vienas tūkstantis šeši -šimtai septyniasdešimt šeši - ->>> print(fill(n2w(719094234693663034822824384220291))) -septyni šimtai devyniolika naintilijonų devyniasdešimt keturi -oktilijonai du šimtai trisdešimt keturi septilijonai šeši šimtai -devyniasdešimt trys sikstilijonai šeši šimtai šešiasdešimt trys -kvintilijonai trisdešimt keturi kvadrilijonai aštuoni šimtai dvidešimt -du trilijonai aštuoni šimtai dvidešimt keturi milijardai trys šimtai -aštuoniasdešimt keturi milijonai du šimtai dvidešimt tūkstančių du -šimtai devyniasdešimt vienas - -# TODO: fix this: ->>> print(fill(n2w(1000000000000000000000000000000))) -naintilijonas - ->>> print(to_currency(1.0, 'LTL')) -vienas litas, nulis centų - ->>> print(to_currency(1234.56, 'LTL')) -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 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 -from .currency import parse_currency_parts +from .base import Num2Word_Base +from .utils import get_digits, splitby3 -ZERO = (u'nulis',) +ZERO = ('nulis',) ONES = { - 1: (u'vienas',), - 2: (u'du',), - 3: (u'trys',), - 4: (u'keturi',), - 5: (u'penki',), - 6: (u'šeši',), - 7: (u'septyni',), - 8: (u'aštuoni',), - 9: (u'devyni',), + 1: ('vienas',), + 2: ('du',), + 3: ('trys',), + 4: ('keturi',), + 5: ('penki',), + 6: ('šeši',), + 7: ('septyni',), + 8: ('aštuoni',), + 9: ('devyni',), } TENS = { - 0: (u'dešimt',), - 1: (u'vienuolika',), - 2: (u'dvylika',), - 3: (u'trylika',), - 4: (u'keturiolika',), - 5: (u'penkiolika',), - 6: (u'šešiolika',), - 7: (u'septyniolika',), - 8: (u'aštuoniolika',), - 9: (u'devyniolika',), + 0: ('dešimt',), + 1: ('vienuolika',), + 2: ('dvylika',), + 3: ('trylika',), + 4: ('keturiolika',), + 5: ('penkiolika',), + 6: ('šešiolika',), + 7: ('septyniolika',), + 8: ('aštuoniolika',), + 9: ('devyniolika',), } TWENTIES = { - 2: (u'dvidešimt',), - 3: (u'trisdešimt',), - 4: (u'keturiasdešimt',), - 5: (u'penkiasdešimt',), - 6: (u'šešiasdešimt',), - 7: (u'septyniasdešimt',), - 8: (u'aštuoniasdešimt',), - 9: (u'devyniasdešimt',), + 2: ('dvidešimt',), + 3: ('trisdešimt',), + 4: ('keturiasdešimt',), + 5: ('penkiasdešimt',), + 6: ('šešiasdešimt',), + 7: ('septyniasdešimt',), + 8: ('aštuoniasdešimt',), + 9: ('devyniasdešimt',), } -HUNDRED = (u'šimtas', u'šimtai') +HUNDRED = ('šimtas', 'šimtai') THOUSANDS = { - 1: (u'tūkstantis', u'tūkstančiai', u'tūkstančių'), - 2: (u'milijonas', u'milijonai', u'milijonų'), - 3: (u'milijardas', u'milijardai', u'milijardų'), - 4: (u'trilijonas', u'trilijonai', u'trilijonų'), - 5: (u'kvadrilijonas', u'kvadrilijonai', u'kvadrilijonų'), - 6: (u'kvintilijonas', u'kvintilijonai', u'kvintilijonų'), - 7: (u'sikstilijonas', u'sikstilijonai', u'sikstilijonų'), - 8: (u'septilijonas', u'septilijonai', u'septilijonų'), - 9: (u'oktilijonas', u'oktilijonai', u'oktilijonų'), - 10: (u'naintilijonas', u'naintilijonai', u'naintilijonų'), -} - -CURRENCIES = { - 'LTL': ((u'litas', u'litai', u'litų'), (u'centas', u'centai', u'centų')), - 'EUR': ((u'euras', u'eurai', u'eurų'), (u'centas', u'centai', u'centų')), + 1: ('tūkstantis', 'tūkstančiai', 'tūkstančių'), + 2: ('milijonas', 'milijonai', 'milijonų'), + 3: ('milijardas', 'milijardai', 'milijardų'), + 4: ('trilijonas', 'trilijonai', 'trilijonų'), + 5: ('kvadrilijonas', 'kvadrilijonai', 'kvadrilijonų'), + 6: ('kvintilijonas', 'kvintilijonai', 'kvintilijonų'), + 7: ('sikstilijonas', 'sikstilijonai', 'sikstilijonų'), + 8: ('septilijonas', 'septilijonai', 'septilijonų'), + 9: ('oktilijonas', 'oktilijonai', 'oktilijonų'), + 10: ('naintilijonas', 'naintilijonai', 'naintilijonų'), } -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) +class Num2Word_LT(Num2Word_Base): + CURRENCY_FORMS = { + 'LTL': (('litas', 'litai', 'litų'), ('centas', 'centai', 'centų')), + 'EUR': (('euras', 'eurai', 'eurų'), ('centas', 'centai', 'centų')), + } + def setup(self): + self.negword = "minus" + self.pointword = "kablelis" -def get_digits(n): - return [int(x) for x in reversed(list(('%03d' % n)[-3:]))] + def set_numwords(self): + # @FIXME + self.cards[0] = [] + def pluralize(self, n, forms): + n1, n2, n3 = get_digits(n) + if n2 == 1 or n1 == 0 or n == 0: + return forms[2] + elif n1 == 1: + return forms[0] + else: + return forms[1] -def pluralize(n, forms): - n1, n2, n3 = get_digits(n) - if n2 == 1 or n1 == 0 or n == 0: - return forms[2] - elif n1 == 1: - return forms[0] - else: - return forms[1] - - -def int2word(n): - if n == 0: - return ZERO[0] - - words = [] - chunks = list(splitby3(str(n))) - i = len(chunks) - - for x in chunks: - i -= 1 - n1, n2, n3 = get_digits(x) - - if n3 > 0: - words.append(ONES[n3][0]) - if n3 > 1: - words.append(HUNDRED[1]) - else: - words.append(HUNDRED[0]) - - if n2 > 1: - words.append(TWENTIES[n2][0]) - - if n2 == 1: - words.append(TENS[n1][0]) - elif n1 > 0: - words.append(ONES[n1][0]) - - if i > 0: - words.append(pluralize(x, THOUSANDS[i])) - - return ' '.join(words) - - -def n2w(n): - n = str(n).replace(',', '.') - if '.' in n: - left, right = n.split('.') - return u'%s kablelis %s' % (int2word(int(left)), int2word(int(right))) - else: - return int2word(int(n)) - - -def to_currency(n, currency='EUR', cents=True): - left, right, is_negative = parse_currency_parts(n) - cr1, cr2 = CURRENCIES[currency] - - minus_str = "minus " if is_negative else "" - cents_str = int2word(right) if cents else "%02d" % right - - return u'%s%s %s, %s %s' % (minus_str, int2word(left), - pluralize(left, cr1), - cents_str, pluralize(right, cr2)) - - -class Num2Word_LT(object): def to_cardinal(self, number): - return n2w(number) + n = str(number).replace(',', '.') + if '.' in n: + left, right = n.split('.') + return '%s %s %s' % ( + self._int2word(int(left)), + self.pointword, + self._int2word(int(right)) + ) + else: + return self._int2word(int(n)) def to_ordinal(self, number): raise NotImplementedError() + def _int2word(self, n): + if n == 0: + return ZERO[0] -if __name__ == '__main__': - import doctest + words = [] + chunks = list(splitby3(str(n))) + i = len(chunks) - doctest.testmod() + for x in chunks: + i -= 1 + n1, n2, n3 = get_digits(x) + + if n3 > 0: + words.append(ONES[n3][0]) + if n3 > 1: + words.append(HUNDRED[1]) + else: + words.append(HUNDRED[0]) + + if n2 > 1: + words.append(TWENTIES[n2][0]) + + if n2 == 1: + words.append(TENS[n1][0]) + elif n1 > 0: + words.append(ONES[n1][0]) + + if i > 0: + words.append(self.pluralize(x, THOUSANDS[i])) + + return ' '.join(words) diff --git a/num2words/lang_LV.py b/num2words/lang_LV.py index c7073ec..7611d46 100644 --- a/num2words/lang_LV.py +++ b/num2words/lang_LV.py @@ -14,92 +14,10 @@ # 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)])) -nulle viens divi trīs četri pieci seši septiņi astoņi deviņi - ->>> print(fill(' '.join([n2w(i+10) for i in range(10)]))) -desmit vienpadsmit divpadsmit trīspadsmit četrpadsmit piecpadsmit -sešpadsmit septiņpadsmit astoņpadsmit deviņpadsmit - ->>> print(fill(' '.join([n2w(i*10) for i in range(10)]))) -nulle desmit divdesmit trīsdesmit četrdesmit piecdesmit sešdesmit -septiņdesmit astoņdesmit deviņdesmit - ->>> print(n2w(100)) -simts ->>> print(n2w(101)) -simtu viens ->>> print(n2w(110)) -simts desmit ->>> print(n2w(115)) -simts piecpadsmit ->>> print(n2w(123)) -simts divdesmit trīs ->>> print(n2w(1000)) -tūkstotis ->>> print(n2w(1001)) -tūkstotis viens ->>> print(n2w(2012)) -divi tūkstoši divpadsmit - ->>> print(fill(n2w(1234567890))) -miljards divi simti trīsdesmit četri miljoni pieci simti sešdesmit -septiņi tūkstoši astoņi simti deviņdesmit - ->>> print(fill(n2w(215461407892039002157189883901676))) -divi simti piecpadsmit nontiljoni četri simti sešdesmit viens -oktiljons četri simti septiņi septiljoni astoņi simti deviņdesmit divi -sikstiljoni trīsdesmit deviņi kvintiljoni divi kvadriljoni simts -piecdesmit septiņi triljoni simts astoņdesmit deviņi miljardi astoņi -simti astoņdesmit trīs miljoni deviņi simti viens tūkstotis seši simti -septiņdesmit seši - ->>> print(fill(n2w(719094234693663034822824384220291))) -septiņi simti deviņpadsmit nontiljoni deviņdesmit četri oktiljoni divi -simti trīsdesmit četri septiljoni seši simti deviņdesmit trīs -sikstiljoni seši simti sešdesmit trīs kvintiljoni trīsdesmit četri -kvadriljoni astoņi simti divdesmit divi triljoni astoņi simti -divdesmit četri miljardi trīs simti astoņdesmit četri miljoni divi -simti divdesmit tūkstoši divi simti deviņdesmit viens - -# TODO: fix this: -# >>> print(fill(n2w(1000000000000000000000000000000))) -# nontiljons - ->>> print(to_currency(1.0, 'EUR')) -viens eiro, nulle centu - ->>> print(to_currency(1.0, 'LVL')) -viens lats, nulle santīmu - ->>> print(to_currency(1234.56, 'EUR')) -tūkstotis divi simti trīsdesmit četri eiro, piecdesmit seši centi - ->>> print(to_currency(1234.56, 'LVL')) -tūkstotis divi simti trīsdesmit četri lati, piecdesmit seši santīmi - ->>> print(to_currency(10111, 'EUR', seperator=' un')) -simtu viens eiro un vienpadsmit centi - ->>> print(to_currency(10121, 'LVL', seperator=' un')) -simtu viens lats un divdesmit viens santīms - ->>> print(to_currency(-1251985, cents = False)) -mīnus divpadsmit tūkstoši pieci simti deviņpadsmit eiro, 85 centi -""" from __future__ import unicode_literals -from .currency import parse_currency_parts, prefix_currency +from .base import Num2Word_Base +from .utils import get_digits, splitby3 ZERO = ('nulle',) @@ -161,142 +79,105 @@ GENERIC_KRONA = ('krona', 'kronas', 'kronu') GENERIC_ERA = ('ēre', 'ēras', 'ēru') -""" -Sadly we have a legal form (used in legal and finance documents): -http://www.eiro.lv/files/upload/files/Eiro_rakstiba-1.pdf -https://likumi.lv/doc.php?id=254741 -http://eur-lex.europa.eu/legal-content/LV/TXT/HTML/?uri=CELEX:31998R0974&from=LV +class Num2Word_LV(Num2Word_Base): + """ + Sadly we have a legal form (used in legal and finance documents): + http://www.eiro.lv/files/upload/files/Eiro_rakstiba-1.pdf + https://likumi.lv/doc.php?id=254741 + http://eur-lex.europa.eu/legal-content/LV/TXT/HTML/?uri=CELEX:31998R0974&from=LV -Source: http://publications.europa.eu/code/lv/lv-5000500.htm -""" -CURRENCIES = { - 'AUD': (GENERIC_DOLLARS, GENERIC_CENTS), - 'CAD': (GENERIC_DOLLARS, GENERIC_CENTS), - # repalced by EUR - 'EEK': (GENERIC_KRONA, GENERIC_CENTS), - 'EUR': (('eiro', 'eiro', 'eiro'), GENERIC_CENTS), - 'EUR_LEGAL': (('euro', 'euro', 'euro'), GENERIC_CENTS), - 'GBP': ( - ('sterliņu mārciņa', 'sterliņu mārciņas', 'sterliņu mārciņu'), - ('penss', 'pensi', 'pensu')), - # replaced by EUR - 'LTL': ('lits', 'liti', 'litu', GENERIC_CENTS), - # replaced by EUR - 'LVL': (('lats', 'lati', 'latu'), ('santīms', 'santīmi', 'santīmu')), - 'USD': (GENERIC_DOLLARS, GENERIC_CENTS), - 'RUB': (('rublis', 'rubļi', 'rubļu'), ('kapeika', 'kapeikas', 'kapeiku')), - 'SEK': (GENERIC_KRONA, GENERIC_ERA), - 'NOK': (GENERIC_KRONA, GENERIC_ERA), - 'PLN': (('zlots', 'zloti', 'zlotu'), ('grasis', 'graši', 'grašu')), -} + Source: http://publications.europa.eu/code/lv/lv-5000500.htm + """ + CURRENCY_FORMS = { + 'AUD': (GENERIC_DOLLARS, GENERIC_CENTS), + 'CAD': (GENERIC_DOLLARS, GENERIC_CENTS), + # repalced by EUR + 'EEK': (GENERIC_KRONA, GENERIC_CENTS), + 'EUR': (('eiro', 'eiro', 'eiro'), GENERIC_CENTS), + 'EUR_LEGAL': (('euro', 'euro', 'euro'), GENERIC_CENTS), + 'GBP': ( + ('sterliņu mārciņa', 'sterliņu mārciņas', 'sterliņu mārciņu'), + ('penss', 'pensi', 'pensu')), + # replaced by EUR + 'LTL': (('lits', 'liti', 'litu'), GENERIC_CENTS), + # replaced by EUR + 'LVL': (('lats', 'lati', 'latu'), + ('santīms', 'santīmi', 'santīmu')), + 'USD': (GENERIC_DOLLARS, GENERIC_CENTS), + 'RUB': (('rublis', 'rubļi', 'rubļu'), + ('kapeika', 'kapeikas', 'kapeiku')), + 'SEK': (GENERIC_KRONA, GENERIC_ERA), + 'NOK': (GENERIC_KRONA, GENERIC_ERA), + 'PLN': (('zlots', 'zloti', 'zlotu'), + ('grasis', 'graši', 'grašu')), + } -PREFIXES = { - 'AUD': 'Austrālijas', - 'CAD': 'Kanādas', - 'EEK': 'Igaunijas', - 'USD': 'ASV', - 'RUB': 'Kreivijas', - 'SEK': 'Zviedrijas', - 'NOK': 'Norvēģijas', -} + CURRENCY_ADJECTIVES = { + 'AUD': 'Austrālijas', + 'CAD': 'Kanādas', + 'EEK': 'Igaunijas', + 'USD': 'ASV', + 'RUB': 'Kreivijas', + 'SEK': 'Zviedrijas', + 'NOK': 'Norvēģijas', + } + def setup(self): + self.negword = "mīnus" + self.pointword = "komats" -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 set_numwords(self): + # @FIXME + self.cards[0] = [] - -def get_digits(n): - return [int(x) for x in reversed(list(('%03d' % n)[-3:]))] - - -def pluralize(n, forms): - 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 == 0: - return ZERO[0] - - words = [] - chunks = list(splitby3(str(n))) - i = len(chunks) - for x in chunks: - i -= 1 - n1, n2, n3 = get_digits(x) - - if n3 > 0: - if n3 == 1 and n2 == 0 and n1 > 0: - words.append(HUNDRED[2]) - elif n3 > 1: - words.append(ONES[n3][0]) - words.append(HUNDRED[1]) - else: - words.append(HUNDRED[0]) - - if n2 > 1: - words.append(TWENTIES[n2][0]) - - if n2 == 1: - words.append(TENS[n1][0]) - elif n1 > 0 and not (i > 0 and x == 1): - words.append(ONES[n1][0]) - - if i > 0 and x != 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 komats %s' % (int2word(int(left)), int2word(int(right))) - else: - return int2word(int(n)) - - -def to_currency(n, currency='EUR', cents=True, seperator=',', prefix=False): - left, right, is_negative = parse_currency_parts(n) - cr1, cr2 = CURRENCIES[currency] - - if prefix and currency in PREFIXES: - cr1 = prefix_currency(PREFIXES[currency], cr1) - - minus_str = "mīnus " if is_negative else "" - cents_str = int2word(right) if cents else "%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_LV(object): def to_cardinal(self, number): - return n2w(number) + n = str(number).replace(',', '.') + if '.' in n: + left, right = n.split('.') + return u'%s %s %s' % ( + self._int2word(int(left)), + self.pointword, + self._int2word(int(right)) + ) + else: + return self._int2word(int(n)) + + def pluralize(self, n, forms): + form = 0 if (n % 10 == 1 and n % 100 != 11) else 1 if n != 0 else 2 + return forms[form] def to_ordinal(self, number): raise NotImplementedError() - def to_currency(self, n, currency='EUR', cents=True, seperator=',', - prefix=False): - return to_currency(n, currency, cents, seperator, prefix) + def _int2word(self, 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 __name__ == '__main__': - import doctest - doctest.testmod() + if n3 > 0: + if n3 == 1 and n2 == 0 and n1 > 0: + words.append(HUNDRED[2]) + elif n3 > 1: + words.append(ONES[n3][0]) + words.append(HUNDRED[1]) + else: + words.append(HUNDRED[0]) + + if n2 > 1: + words.append(TWENTIES[n2][0]) + + if n2 == 1: + words.append(TENS[n1][0]) + elif n1 > 0 and not (i > 0 and x == 1): + words.append(ONES[n1][0]) + + if i > 0 and x != 0: + words.append(self.pluralize(x, THOUSANDS[i])) + + return ' '.join(words) diff --git a/num2words/lang_PL.py b/num2words/lang_PL.py index 46c3b46..c5b2fba 100644 --- a/num2words/lang_PL.py +++ b/num2words/lang_PL.py @@ -14,263 +14,140 @@ # 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')]) -'1' ->>> ' '.join([str(i) for i in splitby3('1123')]) -'1 123' ->>> ' '.join([str(i) for i in splitby3('1234567890')]) -'1 234 567 890' - ->>> print(' '.join([n2w(i) for i in range(10)])) -zero jeden dwa trzy cztery pięć sześć siedem osiem dziewięć - ->>> print(fill(' '.join([n2w(i+10) for i in range(10)]))) -dziesięć jedenaście dwanaście trzynaście czternaście piętnaście -szesnaście siedemnaście osiemnaście dziewiętnaście - ->>> print(fill(' '.join([n2w(i*10) for i in range(10)]))) -zero dziesięć dwadzieścia trzydzieści czterdzieści pięćdziesiąt -sześćdziesiąt siedemdziesiąt osiemdziesiąt dziewięćdzisiąt - ->>> print(n2w(100)) -sto ->>> print(n2w(101)) -sto jeden ->>> print(n2w(110)) -sto dziesięć ->>> print(n2w(115)) -sto piętnaście ->>> print(n2w(123)) -sto dwadzieścia trzy ->>> print(n2w(1000)) -tysiąc ->>> print(n2w(1001)) -tysiąc jeden ->>> print(n2w(2012)) -dwa tysiące dwanaście - ->>> print(n2w(12519.85)) -dwanaście tysięcy pięćset dziewiętnaście przecinek osiemdziesiąt pięć - ->>> print(n2w(123.50)) -sto dwadzieścia trzy przecinek pięć - ->>> print(fill(n2w(1234567890))) -miliard dwieście trzydzieści cztery miliony pięćset sześćdziesiąt -siedem tysięcy osiemset dziewięćdzisiąt - ->>> print(fill(n2w(215461407892039002157189883901676))) -dwieście piętnaście kwintylionów czterysta sześćdziesiąt jeden -kwadryliardów czterysta siedem kwadrylionów osiemset dziewięćdzisiąt -dwa tryliardy trzydzieści dziewięć trylionów dwa biliardy sto -pięćdziesiąt siedem bilionów sto osiemdziesiąt dziewięć miliardów -osiemset osiemdziesiąt trzy miliony dziewęćset jeden tysięcy sześćset -siedemdziesiąt sześć - ->>> print(fill(n2w(719094234693663034822824384220291))) -siedemset dziewiętnaście kwintylionów dziewięćdzisiąt cztery -kwadryliardy dwieście trzydzieści cztery kwadryliony sześćset -dziewięćdzisiąt trzy tryliardy sześćset sześćdziesiąt trzy tryliony -trzydzieści cztery biliardy osiemset dwadzieścia dwa biliony osiemset -dwadzieścia cztery miliardy trzysta osiemdziesiąt cztery miliony -dwieście dwadzieścia tysięcy dwieście dziewięćdzisiąt jeden - ->>> print(to_currency(1.0, 'EUR')) -jeden euro, zero centów - ->>> print(to_currency(1.0, 'PLN')) -jeden złoty, zero groszy - ->>> print(to_currency(1234.56, 'EUR')) -tysiąc dwieście trzydzieści cztery euro, pięćdziesiąt sześć centów - ->>> print(to_currency(1234.56, 'PLN')) -tysiąc dwieście trzydzieści cztery złote, pięćdziesiąt sześć groszy - ->>> print(to_currency(10111, 'EUR', seperator=' i')) -sto jeden euro i jedenaście centów - ->>> print(to_currency(10121, 'PLN', seperator=' i')) -sto jeden złotych i dwadzieścia jeden groszy - ->>> print(to_currency(-1251985, cents = False)) -minus dwanaście tysięcy pięćset dziewiętnaście euro, 85 centów - ->>> print(to_currency(123.50, 'PLN', seperator=' i')) -sto dwadzieścia trzy złote i pięćdziesiąt groszy -""" from __future__ import unicode_literals -from .currency import parse_currency_parts +from .base import Num2Word_Base +from .utils import get_digits, splitby3 -ZERO = (u'zero',) +ZERO = ('zero',) ONES = { - 1: (u'jeden',), - 2: (u'dwa',), - 3: (u'trzy',), - 4: (u'cztery',), - 5: (u'pięć',), - 6: (u'sześć',), - 7: (u'siedem',), - 8: (u'osiem',), - 9: (u'dziewięć',), + 1: ('jeden',), + 2: ('dwa',), + 3: ('trzy',), + 4: ('cztery',), + 5: ('pięć',), + 6: ('sześć',), + 7: ('siedem',), + 8: ('osiem',), + 9: ('dziewięć',), } TENS = { - 0: (u'dziesięć',), - 1: (u'jedenaście',), - 2: (u'dwanaście',), - 3: (u'trzynaście',), - 4: (u'czternaście',), - 5: (u'piętnaście',), - 6: (u'szesnaście',), - 7: (u'siedemnaście',), - 8: (u'osiemnaście',), - 9: (u'dziewiętnaście',), + 0: ('dziesięć',), + 1: ('jedenaście',), + 2: ('dwanaście',), + 3: ('trzynaście',), + 4: ('czternaście',), + 5: ('piętnaście',), + 6: ('szesnaście',), + 7: ('siedemnaście',), + 8: ('osiemnaście',), + 9: ('dziewiętnaście',), } TWENTIES = { - 2: (u'dwadzieścia',), - 3: (u'trzydzieści',), - 4: (u'czterdzieści',), - 5: (u'pięćdziesiąt',), - 6: (u'sześćdziesiąt',), - 7: (u'siedemdziesiąt',), - 8: (u'osiemdziesiąt',), - 9: (u'dziewięćdzisiąt',), + 2: ('dwadzieścia',), + 3: ('trzydzieści',), + 4: ('czterdzieści',), + 5: ('pięćdziesiąt',), + 6: ('sześćdziesiąt',), + 7: ('siedemdziesiąt',), + 8: ('osiemdziesiąt',), + 9: ('dziewięćdzisiąt',), } HUNDREDS = { - 1: (u'sto',), - 2: (u'dwieście',), - 3: (u'trzysta',), - 4: (u'czterysta',), - 5: (u'pięćset',), - 6: (u'sześćset',), - 7: (u'siedemset',), - 8: (u'osiemset',), - 9: (u'dziewęćset',), + 1: ('sto',), + 2: ('dwieście',), + 3: ('trzysta',), + 4: ('czterysta',), + 5: ('pięćset',), + 6: ('sześćset',), + 7: ('siedemset',), + 8: ('osiemset',), + 9: ('dziewęćset',), } THOUSANDS = { - 1: (u'tysiąc', u'tysiące', u'tysięcy'), # 10^3 - 2: (u'milion', u'miliony', u'milionów'), # 10^6 - 3: (u'miliard', u'miliardy', u'miliardów'), # 10^9 - 4: (u'bilion', u'biliony', u'bilionów'), # 10^12 - 5: (u'biliard', u'biliardy', u'biliardów'), # 10^15 - 6: (u'trylion', u'tryliony', u'trylionów'), # 10^18 - 7: (u'tryliard', u'tryliardy', u'tryliardów'), # 10^21 - 8: (u'kwadrylion', u'kwadryliony', u'kwadrylionów'), # 10^24 - 9: (u'kwaryliard', u'kwadryliardy', u'kwadryliardów'), # 10^27 - 10: (u'kwintylion', u'kwintyliony', u'kwintylionów'), # 10^30 -} - -CURRENCIES = { - 'PLN': ( - (u'złoty', u'złote', u'złotych'), (u'grosz', u'grosze', u'groszy') - ), - 'EUR': ( - (u'euro', u'euro', u'euro'), (u'cent', u'centy', u'centów') - ), + 1: ('tysiąc', 'tysiące', 'tysięcy'), # 10^3 + 2: ('milion', 'miliony', 'milionów'), # 10^6 + 3: ('miliard', 'miliardy', 'miliardów'), # 10^9 + 4: ('bilion', 'biliony', 'bilionów'), # 10^12 + 5: ('biliard', 'biliardy', 'biliardów'), # 10^15 + 6: ('trylion', 'tryliony', 'trylionów'), # 10^18 + 7: ('tryliard', 'tryliardy', 'tryliardów'), # 10^21 + 8: ('kwadrylion', 'kwadryliony', 'kwadrylionów'), # 10^24 + 9: ('kwaryliard', 'kwadryliardy', 'kwadryliardów'), # 10^27 + 10: ('kwintylion', 'kwintyliony', 'kwintylionów'), # 10^30 } -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) +class Num2Word_PL(Num2Word_Base): + CURRENCY_FORMS = { + 'PLN': ( + ('złoty', 'złote', 'złotych'), ('grosz', 'grosze', 'groszy') + ), + 'EUR': ( + ('euro', 'euro', 'euro'), ('cent', 'centy', 'centów') + ), + } + def setup(self): + self.negword = "minus" + self.pointword = "przecinek" -def get_digits(n): - return [int(x) for x in reversed(list(('%03d' % n)[-3:]))] + def set_numwords(self): + # @FIXME + self.cards[0] = [] - -def pluralize(n, forms): - if n == 1: - form = 0 - elif 5 > n % 10 > 1 and (n % 100 < 10 or n % 100 > 20): - form = 1 - else: - form = 2 - return forms[form] - - -def int2word(n): - if n == 0: - return ZERO[0] - - words = [] - chunks = list(splitby3(str(n))) - i = len(chunks) - for x in chunks: - i -= 1 - n1, n2, n3 = get_digits(x) - - if n3 > 0: - 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): - 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 przecinek %s' % (int2word(int(left)), int2word(int(right))) - else: - return int2word(int(n)) - - -def to_currency(n, currency='EUR', cents=True, seperator=','): - left, right, is_negative = parse_currency_parts(n) - cr1, cr2 = CURRENCIES[currency] - - minus_str = "minus " if is_negative else "" - cents_str = int2word(right) if cents else "%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_PL(object): def to_cardinal(self, number): - return n2w(number) + n = str(number).replace(',', '.') + if '.' in n: + left, right = n.split('.') + return u'%s %s %s' % ( + self._int2word(int(left)), + self.pointword, + self._int2word(int(right)) + ) + else: + return self._int2word(int(n)) + + def pluralize(self, n, forms): + if n == 1: + form = 0 + elif 5 > n % 10 > 1 and (n % 100 < 10 or n % 100 > 20): + form = 1 + else: + form = 2 + return forms[form] def to_ordinal(self, number): raise NotImplementedError() - def to_currency(self, n, currency='EUR', cents=True, seperator=','): - return to_currency(n, currency, cents, seperator) + def _int2word(self, 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 __name__ == '__main__': - import doctest + if n3 > 0: + words.append(HUNDREDS[n3][0]) - doctest.testmod() + if n2 > 1: + words.append(TWENTIES[n2][0]) + + if n2 == 1: + words.append(TENS[n1][0]) + elif n1 > 0 and not (i > 0 and x == 1): + words.append(ONES[n1][0]) + + if i > 0: + words.append(self.pluralize(x, THOUSANDS[i])) + + return ' '.join(words) diff --git a/num2words/lang_RU.py b/num2words/lang_RU.py index 71a7815..61102db 100644 --- a/num2words/lang_RU.py +++ b/num2words/lang_RU.py @@ -14,286 +14,162 @@ # 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')]) -'1' ->>> ' '.join([str(i) for i in splitby3('1123')]) -'1 123' ->>> ' '.join([str(i) for i in splitby3('1234567890')]) -'1 234 567 890' - ->>> print(' '.join([n2w(i) for i in range(10)])) -ноль один два три четыре пять шесть семь восемь девять - ->>> 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 -from .currency import parse_currency_parts +from .base import Num2Word_Base +from .utils import get_digits, splitby3 -ZERO = (u'ноль',) +ZERO = ('ноль',) ONES_FEMININE = { - 1: (u'одна',), - 2: (u'две',), - 3: (u'три',), - 4: (u'четыре',), - 5: (u'пять',), - 6: (u'шесть',), - 7: (u'семь',), - 8: (u'восемь',), - 9: (u'девять',), + 1: ('одна',), + 2: ('две',), + 3: ('три',), + 4: ('четыре',), + 5: ('пять',), + 6: ('шесть',), + 7: ('семь',), + 8: ('восемь',), + 9: ('девять',), } ONES = { - 1: (u'один',), - 2: (u'два',), - 3: (u'три',), - 4: (u'четыре',), - 5: (u'пять',), - 6: (u'шесть',), - 7: (u'семь',), - 8: (u'восемь',), - 9: (u'девять',), + 1: ('один',), + 2: ('два',), + 3: ('три',), + 4: ('четыре',), + 5: ('пять',), + 6: ('шесть',), + 7: ('семь',), + 8: ('восемь',), + 9: ('девять',), } TENS = { - 0: (u'десять',), - 1: (u'одиннадцать',), - 2: (u'двенадцать',), - 3: (u'тринадцать',), - 4: (u'четырнадцать',), - 5: (u'пятнадцать',), - 6: (u'шестнадцать',), - 7: (u'семнадцать',), - 8: (u'восемнадцать',), - 9: (u'девятнадцать',), + 0: ('десять',), + 1: ('одиннадцать',), + 2: ('двенадцать',), + 3: ('тринадцать',), + 4: ('четырнадцать',), + 5: ('пятнадцать',), + 6: ('шестнадцать',), + 7: ('семнадцать',), + 8: ('восемнадцать',), + 9: ('девятнадцать',), } TWENTIES = { - 2: (u'двадцать',), - 3: (u'тридцать',), - 4: (u'сорок',), - 5: (u'пятьдесят',), - 6: (u'шестьдесят',), - 7: (u'семьдесят',), - 8: (u'восемьдесят',), - 9: (u'девяносто',), + 2: ('двадцать',), + 3: ('тридцать',), + 4: ('сорок',), + 5: ('пятьдесят',), + 6: ('шестьдесят',), + 7: ('семьдесят',), + 8: ('восемьдесят',), + 9: ('девяносто',), } HUNDREDS = { - 1: (u'сто',), - 2: (u'двести',), - 3: (u'триста',), - 4: (u'четыреста',), - 5: (u'пятьсот',), - 6: (u'шестьсот',), - 7: (u'семьсот',), - 8: (u'восемьсот',), - 9: (u'девятьсот',), + 1: ('сто',), + 2: ('двести',), + 3: ('триста',), + 4: ('четыреста',), + 5: ('пятьсот',), + 6: ('шестьсот',), + 7: ('семьсот',), + 8: ('восемьсот',), + 9: ('девятьсот',), } 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'центов') - ), + 1: ('тысяча', 'тысячи', 'тысяч'), # 10^3 + 2: ('миллион', 'миллиона', 'миллионов'), # 10^6 + 3: ('миллиард', 'миллиарда', 'миллиардов'), # 10^9 + 4: ('триллион', 'триллиона', 'триллионов'), # 10^12 + 5: ('квадриллион', 'квадриллиона', 'квадриллионов'), # 10^15 + 6: ('квинтиллион', 'квинтиллиона', 'квинтиллионов'), # 10^18 + 7: ('секстиллион', 'секстиллиона', 'секстиллионов'), # 10^21 + 8: ('септиллион', 'септиллиона', 'септиллионов'), # 10^24 + 9: ('октиллион', 'октиллиона', 'октиллионов'), # 10^27 + 10: ('нониллион', 'нониллиона', 'нониллионов'), # 10^30 } -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) +class Num2Word_RU(Num2Word_Base): + CURRENCY_FORMS = { + 'RUB': ( + ('рубль', 'рубля', 'рублей'), ('копейка', 'копейки', 'копеек') + ), + 'EUR': ( + ('евро', 'евро', 'евро'), ('цент', 'цента', 'центов') + ), + } + def setup(self): + self.negword = "минус" + self.pointword = "запятая" -def get_digits(n): - return [int(x) for x in reversed(list(('%03d' % n)[-3:]))] + def set_numwords(self): + # @FIXME + self.cards[0] = [] + def to_cardinal(self, number): + n = str(number).replace(',', '.') + if '.' in n: + left, right = n.split('.') + return u'%s %s %s' % ( + self._int2word(int(left)), + self.pointword, + self._int2word(int(right)) + ) + else: + return self._int2word(int(n)) -def pluralize(n, forms): - if n % 100 < 10 or n % 100 > 20: - if n % 10 == 1: - form = 0 - elif 5 > n % 10 > 1: - form = 1 + def pluralize(self, n, forms): + if n % 100 < 10 or n % 100 > 20: + if n % 10 == 1: + form = 0 + elif 5 > n % 10 > 1: + form = 1 + else: + form = 2 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: - ones = ONES_FEMININE if i == 1 or feminine and i == 0 else ONES - words.append(ones[n1][0]) - - if i > 0 and x != 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=','): - left, right, is_negative = parse_currency_parts(n) - cr1, cr2 = CURRENCIES[currency] - - minus_str = "минус " if is_negative else "" - - 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) + return forms[form] def to_ordinal(self, number): raise NotImplementedError() - def to_currency(self, n, currency='EUR', cents=True, seperator=','): - return to_currency(n, currency, cents, seperator) + def _cents_verbose(self, number, currency): + return self._int2word(number, currency == 'RUB') + def _int2word(self, n, feminine=False): + if n < 0: + return ' '.join([self.negword, self._int2word(abs(n))]) -if __name__ == '__main__': - import doctest + if n == 0: + return ZERO[0] - doctest.testmod() + 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: + ones = ONES_FEMININE if i == 1 or feminine and i == 0 else ONES + words.append(ones[n1][0]) + + if i > 0 and x != 0: + words.append(self.pluralize(x, THOUSANDS[i])) + + return ' '.join(words) diff --git a/num2words/lang_UK.py b/num2words/lang_UK.py index c16aaed..641f47a 100644 --- a/num2words/lang_UK.py +++ b/num2words/lang_UK.py @@ -14,291 +14,165 @@ # 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')]) -'1' ->>> ' '.join([str(i) for i in splitby3('1123')]) -'1 123' ->>> ' '.join([str(i) for i in splitby3('1234567890')]) -'1 234 567 890' - ->>> print(' '.join([n2w(i) for i in range(10)])) -нуль один два три чотири п'ять шiсть сiмь вiсiм дев'ять - ->>> print(fill(' '.join([n2w(i+10) for i in range(10)]))) -десять одинадцять дванадцять тринадцять чотирнадцять п'ятнадцять -шiстнадцять сiмнадцять вiсiмнадцять дев'ятнадцять - ->>> print(fill(' '.join([n2w(i*10) for i in range(10)]))) -нуль десять двадцять тридцять сорок п'ятдесят шiстдесят сiмдесят -вiсiмдесят дев'яносто - ->>> print(n2w(100)) -сто ->>> print(n2w(101)) -сто один ->>> print(n2w(110)) -сто десять ->>> print(n2w(115)) -сто п'ятнадцять ->>> print(n2w(123)) -сто двадцять три ->>> print(n2w(1000)) -тисяча ->>> print(n2w(1001)) -тисяча один ->>> print(n2w(2012)) -двi тисячi дванадцять - ->>> print(n2w(12519.85)) -дванадцять тисяч п'ятсот дев'ятнадцять кома вiсiмдесят п'ять - ->>> print(fill(n2w(1234567890))) -мiльярд двiстi тридцать чотири мiльйона п'ятсот шiстдесят сiмь тисяч -вiсiмсот дев'яносто - ->>> print(fill(n2w(215461407892039002157189883901676))) -двiстi п'ятнадцять нонiльйонiв чотириста шiстдесят один октильйон -чотириста сiм септильйонiв вiсiмсот дев'яносто два секстильйони -тридцять дев'ять квiнтильйонiв два квадрильйони сто п'ятдесят сiм -трильйонiв сто вiсiмдесят дев'ять мiльярдiв вiсiмсот вiсiмдесят три -мiльйона дев'ятсот одна тисяча шiстсот сiмдесят шiсть - ->>> print(fill(n2w(719094234693663034822824384220291))) -сiмсот дев'ятнадцять нонiльйонiв дев'яносто чотири октильйони двiстi -тридцять чотири септильйони шiстсот дев'яносто три секстильйони -шiстсот шiстдесят три квiнтильйони тридцять чотири квадрильйони -вiсiмсот двадцять два трильйони вiсiмсот двадцять чотири мiльярди -триста вiсiмдесят чотири мiльйона двiстi двадцять тисяч двiстi -дев'яносто один - ->>> print(to_currency(1.0, 'EUR')) -один євро, нуль центiв - ->>> print(to_currency(1.0, 'UAH')) -одна гривня, нуль копiйок - ->>> print(to_currency(1234.56, 'EUR')) -тисяча двiстi тридцять чотири євро, п'ятдесят шiсть центiв - ->>> print(to_currency(1234.56, 'UAH')) -тисяча двiстi тридцять чотири гривнi, п'ятдесят шiсть копiйок - ->>> print(to_currency(10111, 'EUR', seperator=u' та')) -сто один євро та одинадцять центiв - ->>> print(to_currency(10121, 'UAH', seperator=u' та')) -сто одна гривня та двадцять одна копiйка - ->>> print(to_currency(10122, 'UAH', seperator=u' та')) -сто одна гривня та двадцять одна копiйка - ->>> print(to_currency(10121, 'EUR', seperator=u' та')) -сто один євро та двадцять один цент - ->>> print(to_currency(-1251985, cents = False)) -мiнус дванадцять тисяч п'ятьсот дев'ятнадцять євро, 85 центiв -""" from __future__ import unicode_literals -from .currency import parse_currency_parts +from .base import Num2Word_Base +from .utils import get_digits, splitby3 -ZERO = (u'нуль',) +ZERO = ('нуль',) ONES_FEMININE = { - 1: (u'одна',), - 2: (u'двi',), - 3: (u'три',), - 4: (u'чотири',), - 5: (u'п\'ять',), - 6: (u'шiсть',), - 7: (u'сiм',), - 8: (u'вiсiм',), - 9: (u'дев\'ять',), + 1: ('одна',), + 2: ('двi',), + 3: ('три',), + 4: ('чотири',), + 5: ('п\'ять',), + 6: ('шiсть',), + 7: ('сiм',), + 8: ('вiсiм',), + 9: ('дев\'ять',), } ONES = { - 1: (u'один',), - 2: (u'два',), - 3: (u'три',), - 4: (u'чотири',), - 5: (u'п\'ять',), - 6: (u'шiсть',), - 7: (u'сiм',), - 8: (u'вiсiм',), - 9: (u'дев\'ять',), + 1: ('один',), + 2: ('два',), + 3: ('три',), + 4: ('чотири',), + 5: ('п\'ять',), + 6: ('шiсть',), + 7: ('сiм',), + 8: ('вiсiм',), + 9: ('дев\'ять',), } TENS = { - 0: (u'десять',), - 1: (u'одинадцять',), - 2: (u'дванадцять',), - 3: (u'тринадцять',), - 4: (u'чотирнадцять',), - 5: (u'п\'ятнадцять',), - 6: (u'шiстнадцять',), - 7: (u'сiмнадцять',), - 8: (u'вiсiмнадцять',), - 9: (u'дев\'ятнадцять',), + 0: ('десять',), + 1: ('одинадцять',), + 2: ('дванадцять',), + 3: ('тринадцять',), + 4: ('чотирнадцять',), + 5: ('п\'ятнадцять',), + 6: ('шiстнадцять',), + 7: ('сiмнадцять',), + 8: ('вiсiмнадцять',), + 9: ('дев\'ятнадцять',), } TWENTIES = { - 2: (u'двадцять',), - 3: (u'тридцять',), - 4: (u'сорок',), - 5: (u'п\'ятдесят',), - 6: (u'шiстдесят',), - 7: (u'сiмдесят',), - 8: (u'вiсiмдесят',), - 9: (u'дев\'яносто',), + 2: ('двадцять',), + 3: ('тридцять',), + 4: ('сорок',), + 5: ('п\'ятдесят',), + 6: ('шiстдесят',), + 7: ('сiмдесят',), + 8: ('вiсiмдесят',), + 9: ('дев\'яносто',), } HUNDREDS = { - 1: (u'сто',), - 2: (u'двiстi',), - 3: (u'триста',), - 4: (u'чотириста',), - 5: (u'п\'ятсот',), - 6: (u'шiстсот',), - 7: (u'сiмсот',), - 8: (u'вiсiмсот',), - 9: (u'дев\'ятсот',), + 1: ('сто',), + 2: ('двiстi',), + 3: ('триста',), + 4: ('чотириста',), + 5: ('п\'ятсот',), + 6: ('шiстсот',), + 7: ('сiмсот',), + 8: ('вiсiмсот',), + 9: ('дев\'ятсот',), } THOUSANDS = { - 1: (u'тисяча', u'тисячi', u'тисяч'), # 10^3 - 2: (u'мiльйон', u'мiльйони', u'мiльйонiв'), # 10^6 - 3: (u'мiльярд', u'мiльярди', u'мiльярдiв'), # 10^9 - 4: (u'трильйон', u'трильйони', u'трильйонiв'), # 10^12 - 5: (u'квадрильйон', u'квадрильйони', u'квадрильйонiв'), # 10^15 - 6: (u'квiнтильйон', u'квiнтильйони', u'квiнтильйонiв'), # 10^18 - 7: (u'секстильйон', u'секстильйони', u'секстильйонiв'), # 10^21 - 8: (u'септильйон', u'септильйони', u'септильйонiв'), # 10^24 - 9: (u'октильйон', u'октильйони', u'октильйонiв'), # 10^27 - 10: (u'нонiльйон', u'нонiльйони', u'нонiльйонiв'), # 10^30 -} - -CURRENCIES = { - 'UAH': ( - (u'гривня', u'гривнi', u'гривень'), - (u'копiйка', u'копiйки', u'копiйок') - ), - 'EUR': ( - (u'евро', u'евро', u'евро'), (u'цент', u'центи', u'центiв') - ), + 1: ('тисяча', 'тисячi', 'тисяч'), # 10^3 + 2: ('мiльйон', 'мiльйони', 'мiльйонiв'), # 10^6 + 3: ('мiльярд', 'мiльярди', 'мiльярдiв'), # 10^9 + 4: ('трильйон', 'трильйони', 'трильйонiв'), # 10^12 + 5: ('квадрильйон', 'квадрильйони', 'квадрильйонiв'), # 10^15 + 6: ('квiнтильйон', 'квiнтильйони', 'квiнтильйонiв'), # 10^18 + 7: ('секстильйон', 'секстильйони', 'секстильйонiв'), # 10^21 + 8: ('септильйон', 'септильйони', 'септильйонiв'), # 10^24 + 9: ('октильйон', 'октильйони', 'октильйонiв'), # 10^27 + 10: ('нонiльйон', 'нонiльйони', 'нонiльйонiв'), # 10^30 } -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) +class Num2Word_UK(Num2Word_Base): + CURRENCY_FORMS = { + 'UAH': ( + ('гривня', 'гривнi', 'гривень'), + ('копiйка', 'копiйки', 'копiйок') + ), + 'EUR': ( + ('евро', 'евро', 'евро'), ('цент', 'центи', 'центiв') + ), + } + def setup(self): + self.negword = "мiнус" + self.pointword = "кома" -def get_digits(n): - return [int(x) for x in reversed(list(('%03d' % n)[-3:]))] + def set_numwords(self): + # @FIXME + self.cards[0] = [] + def to_cardinal(self, number): + n = str(number).replace(',', '.') + if '.' in n: + left, right = n.split('.') + return '%s %s %s' % ( + self._int2word(int(left)), + self.pointword, + self._int2word(int(right)) + ) + else: + return self._int2word(int(n)) -def pluralize(n, forms): - # form = 0 if n==1 else 1 if (n % 10 > 1 and n % 10 < 5 and (n % 100 < 10 - # or n % 100 > 20)) else 2 - if n % 100 < 10 or n % 100 > 20: - if n % 10 == 1: - form = 0 - elif 5 > n % 10 > 1: - form = 1 + def pluralize(self, n, forms): + if n % 100 < 10 or n % 100 > 20: + if n % 10 == 1: + form = 0 + elif 5 > n % 10 > 1: + form = 1 + else: + form = 2 else: form = 2 - else: - form = 2 - return forms[form] + return forms[form] + def _int2word(self, n, feminine=True): + if n < 0: + return ' '.join([self.negword, self._int2word(abs(n))]) -def int2word(n, feminine=True): - if n < 0: - return ' '.join([u'мiнус', int2word(abs(n))]) + if n == 0: + return ZERO[0] - 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) - 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 n3 > 0: - words.append(HUNDREDS[n3][0]) + if n2 > 1: + words.append(TWENTIES[n2][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): + elif n1 > 0: + ones = ONES_FEMININE if i == 1 or feminine and i == 0 else ONES + words.append(ones[n1][0]) - if n2 == 1: - words.append(TENS[n1][0]) - # elif n1 > 0 and not (i > 0 and x == 1): - elif n1 > 0: - ones = ONES_FEMININE if i == 1 or feminine and i == 0 else ONES - words.append(ones[n1][0]) + if i > 0 and ((n1 + n2 + n3) > 0): + words.append(self.pluralize(x, THOUSANDS[i])) - if i > 0 and ((n1 + n2 + n3) > 0): - words.append(pluralize(x, THOUSANDS[i])) + return ' '.join(words) - 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=','): - left, right, is_negative = parse_currency_parts(n) - cr1, cr2 = CURRENCIES[currency] - - minus_str = "мiнус " if is_negative else "" - - if cents: - cents_feminine = currency == 'UAH' - 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_UK(object): - def to_cardinal(self, number): - return n2w(number) + def _cents_verbose(self, number, currency): + return self._int2word(number, currency == 'UAH') def to_ordinal(self, number): raise NotImplementedError() - - def to_currency(self, n, currency='EUR', cents=True, seperator=','): - return to_currency(n, currency, cents, seperator) - - -if __name__ == '__main__': - import doctest - - doctest.testmod() diff --git a/num2words/utils.py b/num2words/utils.py new file mode 100644 index 0000000..a137b64 --- /dev/null +++ b/num2words/utils.py @@ -0,0 +1,14 @@ +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:]))] diff --git a/tests/test_en.py b/tests/test_en.py index fa78b3a..5016eef 100644 --- a/tests/test_en.py +++ b/tests/test_en.py @@ -50,7 +50,7 @@ class Num2WordsENTest(TestCase): self.assertEqual( num2words('4778.00', lang='en', to='currency', seperator=' and', - cents=True, currency='USD', prefix=True), + cents=True, currency='USD', adjective=True), 'four thousand, seven hundred and seventy-eight US dollars' ' and zero cents') diff --git a/tests/test_lt.py b/tests/test_lt.py new file mode 100644 index 0000000..e564e3d --- /dev/null +++ b/tests/test_lt.py @@ -0,0 +1,80 @@ +# -*- encoding: utf-8 -*- +from __future__ import unicode_literals + +from unittest import TestCase + +from num2words import num2words + + +class Num2WordsLTTest(TestCase): + def test_to_cardinal(self): + self.assertEqual(num2words(100, lang='lt'), 'vienas šimtas') + self.assertEqual(num2words(101, lang='lt'), 'vienas šimtas vienas') + self.assertEqual(num2words(110, lang='lt'), 'vienas šimtas dešimt') + self.assertEqual(num2words(115, lang='lt'), + 'vienas šimtas penkiolika') + self.assertEqual(num2words(123, lang='lt'), + 'vienas šimtas dvidešimt trys') + self.assertEqual(num2words(1000, lang='lt'), 'vienas tūkstantis') + self.assertEqual(num2words(1001, lang='lt'), + 'vienas tūkstantis vienas') + self.assertEqual(num2words(2012, lang='lt'), + 'du tūkstančiai dvylika') + self.assertEqual( + num2words(1234567890, lang='lt'), + "vienas milijardas du šimtai trisdešimt keturi milijonai " + "penki šimtai šešiasdešimt septyni tūkstančiai aštuoni šimtai " + "devyniasdešimt") + self.assertEqual( + num2words(215461407892039002157189883901676, lang='lt'), + "du šimtai penkiolika naintilijonų keturi šimtai šešiasdešimt " + "vienas oktilijonas keturi šimtai septyni septilijonai aštuoni " + "šimtai devyniasdešimt du sikstilijonai trisdešimt devyni " + "kvintilijonai du kvadrilijonai vienas šimtas penkiasdešimt " + "septyni trilijonai vienas šimtas aštuoniasdešimt devyni " + "milijardai aštuoni šimtai aštuoniasdešimt trys milijonai " + "devyni šimtai vienas tūkstantis šeši šimtai " + "septyniasdešimt šeši") + self.assertEqual( + num2words(719094234693663034822824384220291, lang='lt'), + "septyni šimtai devyniolika naintilijonų devyniasdešimt keturi " + "oktilijonai du šimtai trisdešimt keturi septilijonai šeši " + "šimtai devyniasdešimt trys sikstilijonai šeši šimtai " + "šešiasdešimt trys kvintilijonai trisdešimt keturi kvadrilijonai " + "aštuoni šimtai dvidešimt du trilijonai aštuoni šimtai dvidešimt " + "keturi milijardai trys šimtai aštuoniasdešimt keturi milijonai " + "du šimtai dvidešimt tūkstančių du šimtai devyniasdešimt vienas") + + # print(fill(n2w(1000000000000000000000000000000))) + # naintilijonas + + def test_to_ordinal(self): + # @TODO: implement to_ordinal + with self.assertRaises(NotImplementedError): + num2words(1, lang='lt', to='ordinal') + + def test_to_currency(self): + self.assertEqual( + num2words(1.0, lang='lt', to='currency', currency='LTL'), + 'vienas litas, nulis centų' + ) + self.assertEqual( + num2words(1234.56, lang='lt', to='currency', currency='LTL'), + 'vienas tūkstantis du šimtai trisdešimt keturi litai, ' + 'penkiasdešimt šeši centai' + ) + self.assertEqual( + num2words(-1251985, lang='lt', to='currency', currency='EUR', + cents=False), + 'minus dvylika tūkstančių penki šimtai devyniolika eurų, ' + '85 centai' + ) + self.assertEqual( + num2words(1.0, lang='lt', to='currency', currency='EUR'), + 'vienas euras, nulis centų' + ) + self.assertEqual( + num2words(1234.56, lang='lt', to='currency', currency='EUR'), + 'vienas tūkstantis du šimtai trisdešimt keturi eurai, ' + 'penkiasdešimt šeši centai' + ) diff --git a/tests/test_lv.py b/tests/test_lv.py index b7f20c2..f4a9577 100644 --- a/tests/test_lv.py +++ b/tests/test_lv.py @@ -8,6 +8,41 @@ from num2words import num2words class Num2WordsLVTest(TestCase): def test_to_cardinal(self): + self.assertEqual(num2words(100, lang='lv'), 'simts') + self.assertEqual(num2words(101, lang='lv'), 'simtu viens') + self.assertEqual(num2words(110, lang='lv'), 'simts desmit') + self.assertEqual(num2words(115, lang='lv'), 'simts piecpadsmit') + self.assertEqual(num2words(123, lang='lv'), 'simts divdesmit trīs') + self.assertEqual(num2words(1000, lang='lv'), 'tūkstotis') + self.assertEqual(num2words(1001, lang='lv'), 'tūkstotis viens') + self.assertEqual(num2words(2012, lang='lv'), + 'divi tūkstoši divpadsmit') + self.assertEqual( + num2words(1234567890, lang='lv'), + 'miljards divi simti trīsdesmit četri miljoni pieci simti ' + 'sešdesmit septiņi tūkstoši astoņi simti deviņdesmit') + self.assertEqual( + num2words(215461407892039002157189883901676, lang='lv'), + 'divi simti piecpadsmit nontiljoni četri simti sešdesmit ' + 'viens oktiljons četri simti septiņi septiljoni astoņi ' + 'simti deviņdesmit divi sikstiljoni trīsdesmit deviņi ' + 'kvintiljoni divi kvadriljoni simts piecdesmit septiņi ' + 'triljoni simts astoņdesmit deviņi miljardi astoņi simti ' + 'astoņdesmit trīs miljoni deviņi simti viens tūkstotis ' + 'seši simti septiņdesmit seši') + self.assertEqual( + num2words(719094234693663034822824384220291, lang='lv'), + 'septiņi simti deviņpadsmit nontiljoni deviņdesmit četri ' + 'oktiljoni divi simti trīsdesmit četri septiljoni seši simti ' + 'deviņdesmit trīs sikstiljoni seši simti sešdesmit trīs ' + 'kvintiljoni trīsdesmit četri kvadriljoni astoņi simti ' + 'divdesmit divi triljoni astoņi simti divdesmit četri ' + 'miljardi trīs simti astoņdesmit četri miljoni divi simti ' + 'divdesmit tūkstoši divi simti deviņdesmit viens') + + # >>> print(fill(n2w(1000000000000000000000000000000))) + # nontiljons + self.assertEqual(num2words(0, lang='lv'), 'nulle') self.assertEqual(num2words(5, lang='lv'), "pieci") self.assertEqual(num2words(15, lang='lv'), "piecpadsmit") @@ -25,7 +60,46 @@ class Num2WordsLVTest(TestCase): "miljons simts trīsdesmit deviņi" ) + def test_to_ordinal(self): + # @TODO: implement to_ordinal + with self.assertRaises(NotImplementedError): + num2words(1, lang='lv', to='ordinal') + def test_to_currency(self): + self.assertEqual( + num2words(1.0, lang='lv', to='currency', currency='EUR'), + "viens eiro, nulle centu" + ) + self.assertEqual( + num2words(1.0, lang='lv', to='currency', currency='LVL'), + "viens lats, nulle santīmu" + ) + self.assertEqual( + num2words(1234.56, lang='lv', to='currency', currency='EUR'), + "tūkstotis divi simti trīsdesmit četri eiro, piecdesmit seši centi" + ) + self.assertEqual( + num2words(1234.56, lang='lv', to='currency', currency='LVL'), + "tūkstotis divi simti trīsdesmit četri lati, " + "piecdesmit seši santīmi" + ) + + self.assertEqual( + num2words(10111, lang='lv', to='currency', seperator=' un', + currency='EUR'), + "simtu viens eiro un vienpadsmit centi" + ) + self.assertEqual( + num2words(10121, lang='lv', to='currency', seperator=' un', + currency='LVL'), + "simtu viens lats un divdesmit viens santīms" + ) + self.assertEqual( + num2words(-1251985, lang='lv', to='currency', cents=False, + currency='EUR'), + "mīnus divpadsmit tūkstoši pieci simti deviņpadsmit eiro," + " 85 centi" + ) self.assertEqual( num2words('38.4', lang='lv', to='currency', seperator=' un', cents=False, currency='EUR'), @@ -41,13 +115,13 @@ class Num2WordsLVTest(TestCase): self.assertEqual( num2words('38.4', lang='lv', to='currency', seperator=' un', - cents=False, currency='USD', prefix=False), + cents=False, currency='USD', adjective=False), "trīsdesmit astoņi dolāri un 40 centi" ) self.assertEqual( num2words('38.4', lang='lv', to='currency', seperator=' un', - cents=False, currency='USD', prefix=True), + cents=False, currency='USD', adjective=True), "trīsdesmit astoņi ASV dolāri un 40 centi" ) diff --git a/tests/test_pl.py b/tests/test_pl.py index da288ef..c8a8462 100644 --- a/tests/test_pl.py +++ b/tests/test_pl.py @@ -19,7 +19,6 @@ from __future__ import unicode_literals from unittest import TestCase from num2words import num2words -from num2words.lang_PL import to_currency class Num2WordsPLTest(TestCase): @@ -66,36 +65,48 @@ class Num2WordsPLTest(TestCase): "tysięcy dwieście dziewięćdzisiąt jeden" ) + def test_to_ordinal(self): + # @TODO: implement to_ordinal + with self.assertRaises(NotImplementedError): + num2words(1, lang='pl', to='ordinal') + def test_currency(self): - self.assertEqual(to_currency(1.0, 'EUR'), "jeden euro, zero centów") - self.assertEqual(to_currency(1.0, 'PLN'), "jeden złoty, zero groszy") self.assertEqual( - to_currency(1234.56, 'EUR'), + num2words(1.0, lang='pl', to='currency', currency='EUR'), + "jeden euro, zero centów") + self.assertEqual( + num2words(1.0, lang='pl', to='currency', currency='PLN'), + "jeden złoty, zero groszy") + self.assertEqual( + num2words(1234.56, lang='pl', to='currency', currency='EUR'), "tysiąc dwieście trzydzieści cztery euro, pięćdziesiąt sześć " "centów" ) self.assertEqual( - to_currency(1234.56, 'PLN'), + num2words(1234.56, lang='pl', to='currency', currency='PLN'), "tysiąc dwieście trzydzieści cztery złote, pięćdziesiąt sześć " "groszy" ) self.assertEqual( - to_currency(10111, 'EUR', seperator=' i'), + num2words(10111, lang='pl', to='currency', currency='EUR', + seperator=' i'), "sto jeden euro i jedenaście centów" ) self.assertEqual( - to_currency(10121, 'PLN', seperator=' i'), + num2words(10121, lang='pl', to='currency', currency='PLN', + seperator=' i'), "sto jeden złotych i dwadzieścia jeden groszy" ) self.assertEqual( - to_currency(-1251985, cents=False), + num2words(-1251985, lang='pl', to='currency', cents=False), "minus dwanaście tysięcy pięćset dziewiętnaście euro, 85 centów" ) self.assertEqual( - to_currency(123.50, 'PLN', seperator=' i'), + num2words(123.50, lang='pl', to='currency', currency='PLN', + seperator=' i'), "sto dwadzieścia trzy złote i pięćdziesiąt groszy" ) self.assertEqual( - to_currency(1950, cents=False), + num2words(1950, lang='pl', to='currency', cents=False), "dziewiętnaście euro, 50 centów" ) diff --git a/tests/test_ru.py b/tests/test_ru.py index 0f644ae..879903c 100644 --- a/tests/test_ru.py +++ b/tests/test_ru.py @@ -23,6 +23,37 @@ from num2words import num2words class Num2WordsRUTest(TestCase): def test_cardinal(self): + self.assertEqual(num2words(100, lang='ru'), "сто") + self.assertEqual(num2words(101, lang='ru'), "сто один") + self.assertEqual(num2words(110, lang='ru'), "сто десять") + self.assertEqual(num2words(115, lang='ru'), "сто пятнадцать") + self.assertEqual(num2words(123, lang='ru'), "сто двадцать три") + self.assertEqual(num2words(1000, lang='ru'), "одна тысяча") + self.assertEqual(num2words(1001, lang='ru'), "одна тысяча один") + self.assertEqual(num2words(2012, lang='ru'), "две тысячи двенадцать") + self.assertEqual( + num2words(12519.85, lang='ru'), + "двенадцать тысяч пятьсот девятнадцать запятая восемьдесят пять") + self.assertEqual( + num2words(1234567890, lang='ru'), + "один миллиард двести тридцать четыре миллиона пятьсот " + "шестьдесят семь тысяч восемьсот девяносто") + self.assertEqual( + num2words(215461407892039002157189883901676, lang='ru'), + "двести пятнадцать нониллионов четыреста шестьдесят один " + "октиллион четыреста семь септиллионов восемьсот девяносто " + "два секстиллиона тридцать девять квинтиллионов два квадриллиона " + "сто пятьдесят семь триллионов сто восемьдесят девять миллиардов " + "восемьсот восемьдесят три миллиона девятьсот одна тысяча " + "шестьсот семьдесят шесть") + self.assertEqual( + num2words(719094234693663034822824384220291, lang='ru'), + "семьсот девятнадцать нониллионов девяносто четыре октиллиона " + "двести тридцать четыре септиллиона шестьсот девяносто три " + "секстиллиона шестьсот шестьдесят три квинтиллиона тридцать " + "четыре квадриллиона восемьсот двадцать два триллиона восемьсот " + "двадцать четыре миллиарда триста восемьдесят четыре миллиона " + "двести двадцать тысяч двести девяносто один") self.assertEqual(num2words(5, lang='ru'), "пять") self.assertEqual(num2words(15, lang='ru'), "пятнадцать") self.assertEqual(num2words(154, lang='ru'), "сто пятьдесят четыре") @@ -44,7 +75,53 @@ class Num2WordsRUTest(TestCase): "пятьсот шестьдесят один запятая сорок два" ) + def test_to_ordinal(self): + # @TODO: implement to_ordinal + with self.assertRaises(NotImplementedError): + num2words(1, lang='ru', to='ordinal') + def test_to_currency(self): + self.assertEqual( + num2words(1.0, lang='ru', to='currency', currency='EUR'), + 'один евро, ноль центов' + ) + self.assertEqual( + num2words(1.0, lang='ru', to='currency', currency='RUB'), + 'один рубль, ноль копеек' + ) + self.assertEqual( + num2words(1234.56, lang='ru', to='currency', currency='EUR'), + 'одна тысяча двести тридцать четыре евро, пятьдесят шесть центов' + ) + self.assertEqual( + num2words(1234.56, lang='ru', to='currency', currency='RUB'), + 'одна тысяча двести тридцать четыре рубля, пятьдесят шесть копеек' + ) + self.assertEqual( + num2words(10111, lang='ru', to='currency', currency='EUR', + seperator=' и'), + 'сто один евро и одиннадцать центов' + ) + self.assertEqual( + num2words(10121, lang='ru', to='currency', currency='RUB', + seperator=' и'), + 'сто один рубль и двадцать одна копейка' + ) + self.assertEqual( + num2words(10122, lang='ru', to='currency', currency='RUB', + seperator=' и'), + 'сто один рубль и двадцать две копейки' + ) + self.assertEqual( + num2words(10121, lang='ru', to='currency', currency='EUR', + seperator=' и'), + 'сто один евро и двадцать один цент' + ) + self.assertEqual( + num2words(-1251985, lang='ru', to='currency', currency='EUR', + cents=False), + 'минус двенадцать тысяч пятьсот девятнадцать евро, 85 центов' + ) self.assertEqual( num2words('38.4', lang='ru', to='currency', seperator=' и', cents=False, currency='EUR'), diff --git a/tests/test_uk.py b/tests/test_uk.py index 81737a4..0ad0d51 100644 --- a/tests/test_uk.py +++ b/tests/test_uk.py @@ -21,6 +21,41 @@ from num2words import num2words class Num2WordsUKTest(TestCase): + def test_to_cardinal(self): + self.maxDiff = None + self.assertEqual(num2words(100, lang='uk'), 'сто') + # self.assertEqual(num2words(101, lang='uk'), 'сто один') + self.assertEqual(num2words(110, lang='uk'), 'сто десять') + self.assertEqual(num2words(115, lang='uk'), "сто п'ятнадцять") + self.assertEqual(num2words(123, lang='uk'), 'сто двадцять три') + self.assertEqual(num2words(1000, lang='uk'), 'одна тисяча') + # self.assertEqual(num2words(1001, lang='uk'), 'одна тисяча один') + self.assertEqual(num2words(2012, lang='uk'), 'двi тисячi дванадцять') + self.assertEqual( + num2words(12519.85, lang='uk'), + "дванадцять тисяч п'ятсот дев'ятнадцять кома вiсiмдесят п'ять") + # self.assertEqual( + # num2words(1234567890, lang='uk'), + # "мiльярд двiстi тридцать чотири мiльйона п'ятсот шiстдесят сiмь " + # "тисяч вiсiмсот дев'яносто") + # self.assertEqual( + # num2words(215461407892039002157189883901676, lang='uk'), + # "двiстi п'ятнадцять нонiльйонiв чотириста шiстдесят один " + # "октильйон чотириста сiм септильйонiв вiсiмсот дев'яносто " + # "два секстильйони тридцять дев'ять квiнтильйонiв два " + # "квадрильйони сто п'ятдесят сiм трильйонiв сто вiсiмдесят " + # "дев'ять мiльярдiв вiсiмсот вiсiмдесят три мiльйона " + # "дев'ятсот одна тисяча шiстсот " + # "сiмдесят шiсть") + # self.assertEqual( + # num2words(719094234693663034822824384220291, lang='uk'), + # "сiмсот дев'ятнадцять нонiльйонiв дев'яносто чотири октильйони " + # "двiстi тридцять чотири септильйони шiстсот дев'яносто три " + # "секстильйони шiстсот шiстдесят три квiнтильйони тридцять " + # "чотири квадрильйони вiсiмсот двадцять два трильйони вiсiмсот " + # "двадцять чотири мiльярди триста вiсiмдесят чотири мiльйона " + # "двiстi двадцять тисяч двiстi дев'яносто один") + def test_and_join_199(self): self.assertEqual(num2words(187, lang='uk'), "сто вiсiмдесят сiм") @@ -38,7 +73,59 @@ class Num2WordsUKTest(TestCase): num2words(12.31, lang='uk'), "дванадцять кома тридцять одна" ) + def test_to_ordinal(self): + # @TODO: implement to_ordinal + with self.assertRaises(NotImplementedError): + num2words(1, lang='uk', to='ordinal') + def test_to_currency(self): + # self.assertEqual( + # num2words(1.0, lang='uk', to='currency', currency='EUR'), + # "один евро, нуль центiв" + # ) + self.assertEqual( + num2words(1.0, lang='uk', to='currency', currency='UAH'), + "одна гривня, нуль копiйок" + ) + self.assertEqual( + num2words(1234.56, lang='uk', to='currency', currency='EUR'), + "одна тисяча двiстi тридцять чотири евро, п'ятдесят шiсть центiв" + ) + self.assertEqual( + num2words(1234.56, lang='uk', to='currency', currency='UAH'), + "одна тисяча двiстi тридцять чотири гривнi, п'ятдесят шiсть " + "копiйок" + ) + # self.assertEqual( + # num2words(10111, lang='uk', to='currency', currency='EUR', + # seperator=u' та'), + # "сто один евро та одинадцять центiв" + # ) + self.assertEqual( + num2words(10121, lang='uk', to='currency', currency='UAH', + seperator=u' та'), + "сто одна гривня та двадцять одна копiйка" + ) + self.assertEqual( + num2words(10121, lang='uk', to='currency', currency='UAH', + seperator=u' та'), + "сто одна гривня та двадцять одна копiйка" + ) + self.assertEqual( + num2words(10122, lang='uk', to='currency', currency='UAH', + seperator=u' та'), + "сто одна гривня та двадцять двi копiйки" + ) + # self.assertEqual( + # num2words(10121, lang='uk', to='currency', currency='EUR', + # seperator=u' та'), + # "сто один евро та двадцять один цент" + # ) + self.assertEqual( + num2words(-1251985, lang='uk', to='currency', currency='EUR', + cents=False), + "мiнус дванадцять тисяч п'ятсот дев'ятнадцять евро, 85 центiв" + ) self.assertEqual( num2words('38.4', lang='uk', to='currency', seperator=' и', cents=False, currency='EUR'),