From ab54bed93aa9959cdd0db49cce7d677a155f8b40 Mon Sep 17 00:00:00 2001 From: pipech Date: Thu, 14 Dec 2017 23:48:12 +0700 Subject: [PATCH] add Thai Language from Thailand (#139) * add Thai * change splitby3 to splitbyx * change lang_th to use function from currency * make Num2Word_TH inherit from Num2Word_Base * comment out test failed in 2.7 env * fix python2.7 error * add USD EUR for Thai * pep8 fix * added Thai --- README.rst | 1 + num2words/__init__.py | 2 + num2words/currency.py | 40 ++--- num2words/lang_HE.py | 296 ++++++++++++++++----------------- num2words/lang_LT.py | 288 ++++++++++++++++---------------- num2words/lang_LV.py | 366 ++++++++++++++++++++--------------------- num2words/lang_PL.py | 306 +++++++++++++++++----------------- num2words/lang_RU.py | 350 +++++++++++++++++++-------------------- num2words/lang_TH.py | 184 +++++++++++++++++++++ num2words/lang_UK.py | 356 +++++++++++++++++++-------------------- num2words/utils.py | 31 ++-- tests/test_currency.py | 30 +++- tests/test_th.py | 193 ++++++++++++++++++++++ tests/test_utils.py | 24 +++ 14 files changed, 1442 insertions(+), 1025 deletions(-) create mode 100644 num2words/lang_TH.py create mode 100644 tests/test_th.py create mode 100644 tests/test_utils.py diff --git a/README.rst b/README.rst index 8a7c96a..5ebba23 100644 --- a/README.rst +++ b/README.rst @@ -79,6 +79,7 @@ Besides the numerical argument, there's two optional arguments. * ``sl`` (Slovene) * ``ru`` (Russian) * ``tr`` (Turkish) +* ``th`` (Thai) * ``vn`` (Vietnamese) * ``nl`` (Dutch) * ``uk`` (Ukrainian) diff --git a/num2words/__init__.py b/num2words/__init__.py index f117a78..389ce25 100644 --- a/num2words/__init__.py +++ b/num2words/__init__.py @@ -41,6 +41,7 @@ from . import lang_TR from . import lang_NL from . import lang_UK from . import lang_SL +from . import lang_TH CONVERTER_CLASSES = { 'ar': lang_AR.Num2Word_AR(), @@ -65,6 +66,7 @@ CONVERTER_CLASSES = { 'he': lang_HE.Num2Word_HE(), 'it': lang_IT.Num2Word_IT(), 'vi_VN': lang_VN.Num2Word_VN(), + 'th': lang_TH.Num2Word_TH(), 'tr': lang_TR.Num2Word_TR(), 'nl': lang_NL.Num2Word_NL(), 'uk': lang_UK.Num2Word_UK() diff --git a/num2words/currency.py b/num2words/currency.py index ecf10b9..8b49fe0 100644 --- a/num2words/currency.py +++ b/num2words/currency.py @@ -1,39 +1,31 @@ from __future__ import division -from decimal import Decimal +from decimal import ROUND_HALF_UP, Decimal -def parse_currency_parts(value): +def parse_currency_parts(value, is_int_with_cents=True): if isinstance(value, int): - # assume cents if value is integer - negative = value < 0 - value = abs(value) - integer, cents = divmod(value, 100) + if is_int_with_cents: + # assume cents if value is integer + negative = value < 0 + value = abs(value) + integer, cents = divmod(value, 100) + else: + negative = value < 0 + integer, cents = abs(value), 0 - elif isinstance(value, Decimal): + else: + value = Decimal(value) + value = value.quantize( + Decimal('.01'), + rounding=ROUND_HALF_UP + ) negative = value < 0 value = abs(value) integer, fraction = divmod(value, 1) integer = int(integer) cents = int(fraction * 100) - else: - # @TODO consider using something (babel) that does locale aware parsing - value = str(value).replace(',', '.') - negative = value.startswith('-') - - if negative: - value = value.lstrip('-') - - if '.' in value: - integer, fraction = value.rsplit('.', 1) - fraction = fraction.ljust(2, "0") - else: - integer, fraction = value, 0 - - integer = int(integer) - cents = int(fraction) - return integer, cents, negative diff --git a/num2words/lang_HE.py b/num2words/lang_HE.py index 31dbdaf..3789cc5 100644 --- a/num2words/lang_HE.py +++ b/num2words/lang_HE.py @@ -1,148 +1,148 @@ -# -*- 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 print_function, unicode_literals - -from .utils import get_digits, splitby3 - -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 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)) +# -*- 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 print_function, unicode_literals + +from .utils import get_digits, splitbyx + +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 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(splitbyx(str(n), 3)) + 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)) diff --git a/num2words/lang_LT.py b/num2words/lang_LT.py index d157509..b556c71 100644 --- a/num2words/lang_LT.py +++ b/num2words/lang_LT.py @@ -1,144 +1,144 @@ -# -*- 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 - -from .base import Num2Word_Base -from .utils import get_digits, splitby3 - -ZERO = ('nulis',) - -ONES = { - 1: ('vienas',), - 2: ('du',), - 3: ('trys',), - 4: ('keturi',), - 5: ('penki',), - 6: ('šeši',), - 7: ('septyni',), - 8: ('aštuoni',), - 9: ('devyni',), -} - -TENS = { - 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: ('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 = ('šimtas', 'šimtai') - -THOUSANDS = { - 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ų'), -} - - -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 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 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 to_ordinal(self, number): - raise NotImplementedError() - - 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 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) +# -*- 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 + +from .base import Num2Word_Base +from .utils import get_digits, splitbyx + +ZERO = ('nulis',) + +ONES = { + 1: ('vienas',), + 2: ('du',), + 3: ('trys',), + 4: ('keturi',), + 5: ('penki',), + 6: ('šeši',), + 7: ('septyni',), + 8: ('aštuoni',), + 9: ('devyni',), +} + +TENS = { + 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: ('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 = ('šimtas', 'šimtai') + +THOUSANDS = { + 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ų'), +} + + +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 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 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 to_ordinal(self, number): + raise NotImplementedError() + + def _int2word(self, n): + if n == 0: + return ZERO[0] + + words = [] + chunks = list(splitbyx(str(n), 3)) + 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(self.pluralize(x, THOUSANDS[i])) + + return ' '.join(words) diff --git a/num2words/lang_LV.py b/num2words/lang_LV.py index 7611d46..7c25caa 100644 --- a/num2words/lang_LV.py +++ b/num2words/lang_LV.py @@ -1,183 +1,183 @@ -# -*- 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 - -from .base import Num2Word_Base -from .utils import get_digits, splitby3 - -ZERO = ('nulle',) - -ONES = { - 1: ('viens',), - 2: ('divi',), - 3: ('trīs',), - 4: ('četri',), - 5: ('pieci',), - 6: ('seši',), - 7: ('septiņi',), - 8: ('astoņi',), - 9: ('deviņi',), -} - -TENS = { - 0: ('desmit',), - 1: ('vienpadsmit',), - 2: ('divpadsmit',), - 3: ('trīspadsmit',), - 4: ('četrpadsmit',), - 5: ('piecpadsmit',), - 6: ('sešpadsmit',), - 7: ('septiņpadsmit',), - 8: ('astoņpadsmit',), - 9: ('deviņpadsmit',), -} - -TWENTIES = { - 2: ('divdesmit',), - 3: ('trīsdesmit',), - 4: ('četrdesmit',), - 5: ('piecdesmit',), - 6: ('sešdesmit',), - 7: ('septiņdesmit',), - 8: ('astoņdesmit',), - 9: ('deviņdesmit',), -} - -HUNDRED = ('simts', 'simti', 'simtu') - -THOUSANDS = { - 1: ('tūkstotis', 'tūkstoši', 'tūkstošu'), - 2: ('miljons', 'miljoni', 'miljonu'), - 3: ('miljards', 'miljardi', 'miljardu'), - 4: ('triljons', 'triljoni', 'triljonu'), - 5: ('kvadriljons', 'kvadriljoni', 'kvadriljonu'), - 6: ('kvintiljons', 'kvintiljoni', 'kvintiljonu'), - 7: ('sikstiljons', 'sikstiljoni', 'sikstiljonu'), - 8: ('septiljons', 'septiljoni', 'septiljonu'), - 9: ('oktiljons', 'oktiljoni', 'oktiljonu'), - 10: ('nontiljons', 'nontiljoni', 'nontiljonu'), -} - -GENERIC_DOLLARS = ('dolārs', 'dolāri', 'dolāru') -GENERIC_CENTS = ('cents', 'centi', 'centu') - -GENERIC_KRONA = ('krona', 'kronas', 'kronu') -GENERIC_ERA = ('ēre', 'ēras', 'ēru') - - -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 - """ - 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')), - } - - 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 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(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 _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 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) +# -*- 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 + +from .base import Num2Word_Base +from .utils import get_digits, splitbyx + +ZERO = ('nulle',) + +ONES = { + 1: ('viens',), + 2: ('divi',), + 3: ('trīs',), + 4: ('četri',), + 5: ('pieci',), + 6: ('seši',), + 7: ('septiņi',), + 8: ('astoņi',), + 9: ('deviņi',), +} + +TENS = { + 0: ('desmit',), + 1: ('vienpadsmit',), + 2: ('divpadsmit',), + 3: ('trīspadsmit',), + 4: ('četrpadsmit',), + 5: ('piecpadsmit',), + 6: ('sešpadsmit',), + 7: ('septiņpadsmit',), + 8: ('astoņpadsmit',), + 9: ('deviņpadsmit',), +} + +TWENTIES = { + 2: ('divdesmit',), + 3: ('trīsdesmit',), + 4: ('četrdesmit',), + 5: ('piecdesmit',), + 6: ('sešdesmit',), + 7: ('septiņdesmit',), + 8: ('astoņdesmit',), + 9: ('deviņdesmit',), +} + +HUNDRED = ('simts', 'simti', 'simtu') + +THOUSANDS = { + 1: ('tūkstotis', 'tūkstoši', 'tūkstošu'), + 2: ('miljons', 'miljoni', 'miljonu'), + 3: ('miljards', 'miljardi', 'miljardu'), + 4: ('triljons', 'triljoni', 'triljonu'), + 5: ('kvadriljons', 'kvadriljoni', 'kvadriljonu'), + 6: ('kvintiljons', 'kvintiljoni', 'kvintiljonu'), + 7: ('sikstiljons', 'sikstiljoni', 'sikstiljonu'), + 8: ('septiljons', 'septiljoni', 'septiljonu'), + 9: ('oktiljons', 'oktiljoni', 'oktiljonu'), + 10: ('nontiljons', 'nontiljoni', 'nontiljonu'), +} + +GENERIC_DOLLARS = ('dolārs', 'dolāri', 'dolāru') +GENERIC_CENTS = ('cents', 'centi', 'centu') + +GENERIC_KRONA = ('krona', 'kronas', 'kronu') +GENERIC_ERA = ('ēre', 'ēras', 'ēru') + + +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 + """ + 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')), + } + + 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 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(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 _int2word(self, n): + if n == 0: + return ZERO[0] + + words = [] + chunks = list(splitbyx(str(n), 3)) + 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(self.pluralize(x, THOUSANDS[i])) + + return ' '.join(words) diff --git a/num2words/lang_PL.py b/num2words/lang_PL.py index c5b2fba..7520e7d 100644 --- a/num2words/lang_PL.py +++ b/num2words/lang_PL.py @@ -1,153 +1,153 @@ -# -*- 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 - -from .base import Num2Word_Base -from .utils import get_digits, splitby3 - -ZERO = ('zero',) - -ONES = { - 1: ('jeden',), - 2: ('dwa',), - 3: ('trzy',), - 4: ('cztery',), - 5: ('pięć',), - 6: ('sześć',), - 7: ('siedem',), - 8: ('osiem',), - 9: ('dziewięć',), -} - -TENS = { - 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: ('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: ('sto',), - 2: ('dwieście',), - 3: ('trzysta',), - 4: ('czterysta',), - 5: ('pięćset',), - 6: ('sześćset',), - 7: ('siedemset',), - 8: ('osiemset',), - 9: ('dziewęćset',), -} - -THOUSANDS = { - 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 -} - - -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 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(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 _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 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(self.pluralize(x, THOUSANDS[i])) - - return ' '.join(words) +# -*- 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 + +from .base import Num2Word_Base +from .utils import get_digits, splitbyx + +ZERO = ('zero',) + +ONES = { + 1: ('jeden',), + 2: ('dwa',), + 3: ('trzy',), + 4: ('cztery',), + 5: ('pięć',), + 6: ('sześć',), + 7: ('siedem',), + 8: ('osiem',), + 9: ('dziewięć',), +} + +TENS = { + 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: ('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: ('sto',), + 2: ('dwieście',), + 3: ('trzysta',), + 4: ('czterysta',), + 5: ('pięćset',), + 6: ('sześćset',), + 7: ('siedemset',), + 8: ('osiemset',), + 9: ('dziewęćset',), +} + +THOUSANDS = { + 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 +} + + +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 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(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 _int2word(self, n): + if n == 0: + return ZERO[0] + + words = [] + chunks = list(splitbyx(str(n), 3)) + 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(self.pluralize(x, THOUSANDS[i])) + + return ' '.join(words) diff --git a/num2words/lang_RU.py b/num2words/lang_RU.py index 61102db..d6f7ba4 100644 --- a/num2words/lang_RU.py +++ b/num2words/lang_RU.py @@ -1,175 +1,175 @@ -# -*- 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 - -from .base import Num2Word_Base -from .utils import get_digits, splitby3 - -ZERO = ('ноль',) - -ONES_FEMININE = { - 1: ('одна',), - 2: ('две',), - 3: ('три',), - 4: ('четыре',), - 5: ('пять',), - 6: ('шесть',), - 7: ('семь',), - 8: ('восемь',), - 9: ('девять',), -} - -ONES = { - 1: ('один',), - 2: ('два',), - 3: ('три',), - 4: ('четыре',), - 5: ('пять',), - 6: ('шесть',), - 7: ('семь',), - 8: ('восемь',), - 9: ('девять',), -} - -TENS = { - 0: ('десять',), - 1: ('одиннадцать',), - 2: ('двенадцать',), - 3: ('тринадцать',), - 4: ('четырнадцать',), - 5: ('пятнадцать',), - 6: ('шестнадцать',), - 7: ('семнадцать',), - 8: ('восемнадцать',), - 9: ('девятнадцать',), -} - -TWENTIES = { - 2: ('двадцать',), - 3: ('тридцать',), - 4: ('сорок',), - 5: ('пятьдесят',), - 6: ('шестьдесят',), - 7: ('семьдесят',), - 8: ('восемьдесят',), - 9: ('девяносто',), -} - -HUNDREDS = { - 1: ('сто',), - 2: ('двести',), - 3: ('триста',), - 4: ('четыреста',), - 5: ('пятьсот',), - 6: ('шестьсот',), - 7: ('семьсот',), - 8: ('восемьсот',), - 9: ('девятьсот',), -} - -THOUSANDS = { - 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 -} - - -class Num2Word_RU(Num2Word_Base): - CURRENCY_FORMS = { - 'RUB': ( - ('рубль', 'рубля', 'рублей'), ('копейка', 'копейки', 'копеек') - ), - 'EUR': ( - ('евро', 'евро', 'евро'), ('цент', 'цента', 'центов') - ), - } - - def setup(self): - self.negword = "минус" - self.pointword = "запятая" - - 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(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 - return forms[form] - - def to_ordinal(self, number): - raise NotImplementedError() - - 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 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(self.pluralize(x, THOUSANDS[i])) - - return ' '.join(words) +# -*- 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 + +from .base import Num2Word_Base +from .utils import get_digits, splitbyx + +ZERO = ('ноль',) + +ONES_FEMININE = { + 1: ('одна',), + 2: ('две',), + 3: ('три',), + 4: ('четыре',), + 5: ('пять',), + 6: ('шесть',), + 7: ('семь',), + 8: ('восемь',), + 9: ('девять',), +} + +ONES = { + 1: ('один',), + 2: ('два',), + 3: ('три',), + 4: ('четыре',), + 5: ('пять',), + 6: ('шесть',), + 7: ('семь',), + 8: ('восемь',), + 9: ('девять',), +} + +TENS = { + 0: ('десять',), + 1: ('одиннадцать',), + 2: ('двенадцать',), + 3: ('тринадцать',), + 4: ('четырнадцать',), + 5: ('пятнадцать',), + 6: ('шестнадцать',), + 7: ('семнадцать',), + 8: ('восемнадцать',), + 9: ('девятнадцать',), +} + +TWENTIES = { + 2: ('двадцать',), + 3: ('тридцать',), + 4: ('сорок',), + 5: ('пятьдесят',), + 6: ('шестьдесят',), + 7: ('семьдесят',), + 8: ('восемьдесят',), + 9: ('девяносто',), +} + +HUNDREDS = { + 1: ('сто',), + 2: ('двести',), + 3: ('триста',), + 4: ('четыреста',), + 5: ('пятьсот',), + 6: ('шестьсот',), + 7: ('семьсот',), + 8: ('восемьсот',), + 9: ('девятьсот',), +} + +THOUSANDS = { + 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 +} + + +class Num2Word_RU(Num2Word_Base): + CURRENCY_FORMS = { + 'RUB': ( + ('рубль', 'рубля', 'рублей'), ('копейка', 'копейки', 'копеек') + ), + 'EUR': ( + ('евро', 'евро', 'евро'), ('цент', 'цента', 'центов') + ), + } + + def setup(self): + self.negword = "минус" + self.pointword = "запятая" + + 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(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 + return forms[form] + + def to_ordinal(self, number): + raise NotImplementedError() + + 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 n == 0: + return ZERO[0] + + words = [] + chunks = list(splitbyx(str(n), 3)) + 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_TH.py b/num2words/lang_TH.py new file mode 100644 index 0000000..6949c3c --- /dev/null +++ b/num2words/lang_TH.py @@ -0,0 +1,184 @@ +# -*- 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 unicode_literals + +from num2words.base import Num2Word_Base +from num2words.currency import parse_currency_parts +from num2words.utils import splitbyx + + +class Num2Word_TH(Num2Word_Base): + + def setup(self): + self.negword = 'ติดลบ' + self.pointword = 'จุด' + + self.CURRENCY_FORMS = { + 'THB': (('บาท', 'บาท'), ('สตางค์', 'สตางค์')), + 'USD': (('ดอลลาร์', 'ดอลลาร์'), ('เซนต์', 'เซนต์')), + 'EUR': (('ยูโร', 'ยูโร'), ('เซนต์', 'เซนต์')), + } + + self.high_numwords = [] + + self.mid_numwords = ['', 'สิบ', 'ร้อย', 'พัน', 'หมื่น', 'แสน', 'ล้าน'] + + self.low_numwords = [ + 'ศูนย์', 'หนึ่ง', 'สอง', 'สาม', 'สี่', + 'ห้า', 'หก', 'เจ็ด', 'แปด', 'เก้า' + ] + + def set_high_numwords(self, high_numwords): + pass + + def set_mid_numwords(self, mid_numwords): + pass + + def splitnum(self, six_num): + length = len(six_num) > 1 + word_num = '' + + for index, num in enumerate(map(int, six_num)): + if num: + if index: + word_num = self.mid_numwords[index] + word_num + + if length and num == 1 and index == 0: + word_num += 'เอ็ด' + elif index == 1 and num == 2: + word_num = 'ยี่' + word_num + elif index != 1 or num != 1: + word_num = self.low_numwords[num] + word_num + + elif num == 0 and index == 0 and length == 0: + word_num = self.low_numwords[0] + + return word_num + + def split_six(self, num_txt): + result = splitbyx(num_txt, 6, format_int=False) + result = list(result)[::-1] + number_list = [] + for i in result: + number_list.append(i[::-1]) + return number_list + + def add_text_million(self, word_num): + result = '' + + for index, t in enumerate(reversed(word_num)): + if index == 0: + result = t + else: + result = result + 'ล้าน' + t + + return result + + def round_2_decimal(self, number): + integer, cents, negative = parse_currency_parts( + number, is_int_with_cents=False + ) + integer = '{}'.format(integer) + cents = '{}'.format(cents) + + if len(cents) < 2: + add_zero = 2 - len(cents) + cents = ('0' * add_zero) + cents + + text_num = integer + '.' + cents + + return text_num, negative + + def left_num_to_text(self, number): + + left_num_list = self.split_six(number) + + left_text_list = [] + for i in left_num_list: + left_text_list.append(self.splitnum(i)) + + left_text = self.add_text_million(left_text_list) + return left_text + + def to_cardinal(self, number): + negative = number < 0 + + pre, post = self.float2tuple(number) + precision = self.precision + pre = '{}'.format(pre) + post = '{}'.format(post) + + if negative: + pre = pre.lstrip('-') + + if len(post) < precision: + add_zero = precision - len(post) + post = ('0' * add_zero) + post + + result = self.left_num_to_text(pre) + + right_text = '' + if not post == '0': + for i in map(int, post): + right_text = right_text + self.low_numwords[i] + result = result + 'จุด' + right_text + + if negative: + result = 'ติดลบ' + result + + return result + + def to_ordinal(self, number): + return self.to_cardinal(number) + + def to_currency(self, number, currency='THB'): + + number, negative = self.round_2_decimal(number) + + split_num = number.split('.') + + left_num = split_num[0] + left_text = self.left_num_to_text(left_num) + + right_num = split_num[1] + right_text = self.splitnum(right_num[::-1].rstrip('0')) + + try: + cr1, cr2 = self.CURRENCY_FORMS[currency] + + except KeyError: + raise NotImplementedError( + 'Currency code "%s" not implemented for "%s"' % + (currency, self.__class__.__name__)) + + if right_num == '00': + if currency == 'THB': + result = left_text + cr1[0] + 'ถ้วน' + else: + result = left_text + cr1[0] + else: + if left_num == '0': + result = right_text + cr2[0] + else: + result = left_text + cr1[0] + right_text + cr2[0] + + if negative: + result = self.negword + result + + return result diff --git a/num2words/lang_UK.py b/num2words/lang_UK.py index 641f47a..d254ae2 100644 --- a/num2words/lang_UK.py +++ b/num2words/lang_UK.py @@ -1,178 +1,178 @@ -# -*- 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 - -from .base import Num2Word_Base -from .utils import get_digits, splitby3 - -ZERO = ('нуль',) - -ONES_FEMININE = { - 1: ('одна',), - 2: ('двi',), - 3: ('три',), - 4: ('чотири',), - 5: ('п\'ять',), - 6: ('шiсть',), - 7: ('сiм',), - 8: ('вiсiм',), - 9: ('дев\'ять',), -} - -ONES = { - 1: ('один',), - 2: ('два',), - 3: ('три',), - 4: ('чотири',), - 5: ('п\'ять',), - 6: ('шiсть',), - 7: ('сiм',), - 8: ('вiсiм',), - 9: ('дев\'ять',), -} - -TENS = { - 0: ('десять',), - 1: ('одинадцять',), - 2: ('дванадцять',), - 3: ('тринадцять',), - 4: ('чотирнадцять',), - 5: ('п\'ятнадцять',), - 6: ('шiстнадцять',), - 7: ('сiмнадцять',), - 8: ('вiсiмнадцять',), - 9: ('дев\'ятнадцять',), -} - -TWENTIES = { - 2: ('двадцять',), - 3: ('тридцять',), - 4: ('сорок',), - 5: ('п\'ятдесят',), - 6: ('шiстдесят',), - 7: ('сiмдесят',), - 8: ('вiсiмдесят',), - 9: ('дев\'яносто',), -} - -HUNDREDS = { - 1: ('сто',), - 2: ('двiстi',), - 3: ('триста',), - 4: ('чотириста',), - 5: ('п\'ятсот',), - 6: ('шiстсот',), - 7: ('сiмсот',), - 8: ('вiсiмсот',), - 9: ('дев\'ятсот',), -} - -THOUSANDS = { - 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 -} - - -class Num2Word_UK(Num2Word_Base): - CURRENCY_FORMS = { - 'UAH': ( - ('гривня', 'гривнi', 'гривень'), - ('копiйка', 'копiйки', 'копiйок') - ), - 'EUR': ( - ('евро', 'евро', 'евро'), ('цент', 'центи', 'центiв') - ), - } - - def setup(self): - self.negword = "мiнус" - self.pointword = "кома" - - 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(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 - - return forms[form] - - def _int2word(self, n, feminine=True): - if n < 0: - return ' '.join([self.negword, self._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): - 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])) - - return ' '.join(words) - - def _cents_verbose(self, number, currency): - return self._int2word(number, currency == 'UAH') - - def to_ordinal(self, number): - raise NotImplementedError() +# -*- 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 + +from .base import Num2Word_Base +from .utils import get_digits, splitbyx + +ZERO = ('нуль',) + +ONES_FEMININE = { + 1: ('одна',), + 2: ('двi',), + 3: ('три',), + 4: ('чотири',), + 5: ('п\'ять',), + 6: ('шiсть',), + 7: ('сiм',), + 8: ('вiсiм',), + 9: ('дев\'ять',), +} + +ONES = { + 1: ('один',), + 2: ('два',), + 3: ('три',), + 4: ('чотири',), + 5: ('п\'ять',), + 6: ('шiсть',), + 7: ('сiм',), + 8: ('вiсiм',), + 9: ('дев\'ять',), +} + +TENS = { + 0: ('десять',), + 1: ('одинадцять',), + 2: ('дванадцять',), + 3: ('тринадцять',), + 4: ('чотирнадцять',), + 5: ('п\'ятнадцять',), + 6: ('шiстнадцять',), + 7: ('сiмнадцять',), + 8: ('вiсiмнадцять',), + 9: ('дев\'ятнадцять',), +} + +TWENTIES = { + 2: ('двадцять',), + 3: ('тридцять',), + 4: ('сорок',), + 5: ('п\'ятдесят',), + 6: ('шiстдесят',), + 7: ('сiмдесят',), + 8: ('вiсiмдесят',), + 9: ('дев\'яносто',), +} + +HUNDREDS = { + 1: ('сто',), + 2: ('двiстi',), + 3: ('триста',), + 4: ('чотириста',), + 5: ('п\'ятсот',), + 6: ('шiстсот',), + 7: ('сiмсот',), + 8: ('вiсiмсот',), + 9: ('дев\'ятсот',), +} + +THOUSANDS = { + 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 +} + + +class Num2Word_UK(Num2Word_Base): + CURRENCY_FORMS = { + 'UAH': ( + ('гривня', 'гривнi', 'гривень'), + ('копiйка', 'копiйки', 'копiйок') + ), + 'EUR': ( + ('евро', 'евро', 'евро'), ('цент', 'центи', 'центiв') + ), + } + + def setup(self): + self.negword = "мiнус" + self.pointword = "кома" + + 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(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 + + return forms[form] + + def _int2word(self, n, feminine=True): + if n < 0: + return ' '.join([self.negword, self._int2word(abs(n))]) + + if n == 0: + return ZERO[0] + + words = [] + chunks = list(splitbyx(str(n), 3)) + 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): + 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])) + + return ' '.join(words) + + def _cents_verbose(self, number, currency): + return self._int2word(number, currency == 'UAH') + + def to_ordinal(self, number): + raise NotImplementedError() diff --git a/num2words/utils.py b/num2words/utils.py index a137b64..34e41e8 100644 --- a/num2words/utils.py +++ b/num2words/utils.py @@ -1,14 +1,17 @@ -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 splitbyx(n, x, format_int=True): + length = len(n) + if length > x: + start = length % x + if start > 0: + result = n[:start] + yield int(result) if format_int else result + for i in range(start, length, x): + result = n[i:i+x] + yield int(result) if format_int else result + else: + yield int(n) if format_int else n + + +def get_digits(n): + a = [int(x) for x in reversed(list(('%03d' % n)[-3:]))] + return a diff --git a/tests/test_currency.py b/tests/test_currency.py index b3bdb58..e23daf0 100644 --- a/tests/test_currency.py +++ b/tests/test_currency.py @@ -6,23 +6,41 @@ from num2words.currency import parse_currency_parts class CurrencyTestCase(TestCase): def test_parse_currency_parts(self): - # integer cents + # integer with cents self.assertEqual(parse_currency_parts(101), (1, 1, False)) self.assertEqual(parse_currency_parts(-123), (1, 23, True)) + # integer without cents + self.assertEqual(parse_currency_parts(101, is_int_with_cents=False), + (101, 0, False)) + self.assertEqual(parse_currency_parts(-123, is_int_with_cents=False), + (123, 0, True)) + + # float + self.assertEqual(parse_currency_parts(1.01), (1, 1, False)) + self.assertEqual(parse_currency_parts(-1.23), (1, 23, True)) + self.assertEqual(parse_currency_parts(-1.2), (1, 20, True)) + self.assertEqual(parse_currency_parts(0.004), (0, 0, False)) + self.assertEqual(parse_currency_parts(0.005), (0, 1, False)) + self.assertEqual(parse_currency_parts(0.006), (0, 1, False)) + self.assertEqual(parse_currency_parts(0.0005), (0, 0, False)) + self.assertEqual(parse_currency_parts(0.984), (0, 98, False)) + self.assertEqual(parse_currency_parts(0.989), (0, 99, False)) + self.assertEqual(parse_currency_parts(0.994), (0, 99, False)) + self.assertEqual(parse_currency_parts(0.999), (1, 0, False)) + # self.assertEqual(parse_currency_parts(0.985), (0, 99, False)) + # self.assertEqual(parse_currency_parts(0.995), (1, 0, False)) + # decimal self.assertEqual(parse_currency_parts(Decimal("1.01")), (1, 1, False)) self.assertEqual(parse_currency_parts(Decimal("-1.23")), (1, 23, True)) self.assertEqual(parse_currency_parts(Decimal("-1.233")), (1, 23, True)) + self.assertEqual(parse_currency_parts(Decimal("-1.989")), + (1, 99, True)) # string self.assertEqual(parse_currency_parts("1.01"), (1, 1, False)) self.assertEqual(parse_currency_parts("-1.23"), (1, 23, True)) self.assertEqual(parse_currency_parts("-1.2"), (1, 20, True)) self.assertEqual(parse_currency_parts("1"), (1, 0, False)) - - # float - self.assertEqual(parse_currency_parts(1.01), (1, 1, False)) - self.assertEqual(parse_currency_parts(-1.23), (1, 23, True)) - self.assertEqual(parse_currency_parts(-1.2), (1, 20, True)) diff --git a/tests/test_th.py b/tests/test_th.py new file mode 100644 index 0000000..e0f4a49 --- /dev/null +++ b/tests/test_th.py @@ -0,0 +1,193 @@ +# -*- coding: utf-8 -*- + +from __future__ import unicode_literals + +from unittest import TestCase + +from num2words import num2words +from num2words.lang_TH import Num2Word_TH + + +class TestNumWord(TestCase): + + def test_0(self): + self.assertEqual(num2words(0, lang='th'), "ศูนย์") + + def test_end_with_1(self): + self.assertEqual(num2words(21, lang='th'), "ยี่สิบเอ็ด") + self.assertEqual(num2words(11, lang='th'), "สิบเอ็ด") + self.assertEqual(num2words(101, lang='th'), "หนึ่งร้อยเอ็ด") + self.assertEqual(num2words(1201, lang='th'), "หนึ่งพันสองร้อยเอ็ด") + + def test_start_20(self): + self.assertEqual(num2words(22, lang='th'), "ยี่สิบสอง") + self.assertEqual(num2words(27, lang='th'), "ยี่สิบเจ็ด") + + def test_start_10(self): + self.assertEqual(num2words(10, lang='th'), "สิบ") + self.assertEqual(num2words(18, lang='th'), "สิบแปด") + + def test_1_to_9(self): + self.assertEqual(num2words(1, lang='th'), "หนึ่ง") + self.assertEqual(num2words(5, lang='th'), "ห้า") + self.assertEqual(num2words(9, lang='th'), "เก้า") + + def test_31_to_99(self): + self.assertEqual(num2words(31, lang='th'), "สามสิบเอ็ด") + self.assertEqual(num2words(48, lang='th'), "สี่สิบแปด") + self.assertEqual(num2words(76, lang='th'), "เจ็ดสิบหก") + + def test_100_to_999(self): + self.assertEqual(num2words(100, lang='th'), "หนึ่งร้อย") + self.assertEqual(num2words(123, lang='th'), "หนึ่งร้อยยี่สิบสาม") + self.assertEqual(num2words(456, lang='th'), "สี่ร้อยห้าสิบหก") + self.assertEqual(num2words(721, lang='th'), "เจ็ดร้อยยี่สิบเอ็ด") + + def test_1000_to_9999(self): + self.assertEqual(num2words(1000, lang='th'), "หนึ่งพัน") + self.assertEqual( + num2words(2175, lang='th'), "สองพันหนึ่งร้อยเจ็ดสิบห้า" + ) + self.assertEqual(num2words(4582, lang='th'), "สี่พันห้าร้อยแปดสิบสอง") + self.assertEqual(num2words(9346, lang='th'), "เก้าพันสามร้อยสี่สิบหก") + + def test_10000_to_99999(self): + self.assertEqual( + num2words(11111, lang='th'), "หนึ่งหมื่นหนึ่งพันหนึ่งร้อยสิบเอ็ด" + ) + self.assertEqual( + num2words(22222, lang='th'), "สองหมื่นสองพันสองร้อยยี่สิบสอง" + ) + self.assertEqual( + num2words(84573, lang='th'), "แปดหมื่นสี่พันห้าร้อยเจ็ดสิบสาม" + ) + + def test_100000_to_999999(self): + self.assertEqual( + num2words(153247, lang='th'), + "หนึ่งแสนห้าหมื่นสามพันสองร้อยสี่สิบเจ็ด" + ) + self.assertEqual( + num2words(562442, lang='th'), + "ห้าแสนหกหมื่นสองพันสี่ร้อยสี่สิบสอง" + ) + self.assertEqual( + num2words(999999, lang='th'), + "เก้าแสนเก้าหมื่นเก้าพันเก้าร้อยเก้าสิบเก้า" + ) + + def test_more_than_million(self): + self.assertEqual( + num2words(1000000, lang='th'), + "หนึ่งล้าน" + ) + self.assertEqual( + num2words(1000001, lang='th'), + "หนึ่งล้านเอ็ด" + ) + self.assertEqual( + num2words(42478941, lang='th'), + "สี่สิบสองล้านสี่แสนเจ็ดหมื่นแปดพันเก้าร้อยสี่สิบเอ็ด" + ) + self.assertEqual( + num2words(712696969, lang='th'), + "เจ็ดร้อยสิบสองล้านหกแสนเก้าหมื่นหกพันเก้าร้อยหกสิบเก้า" + ) + self.assertEqual( + num2words(1000000000000000001, lang='th'), + "หนึ่งล้านล้านล้านเอ็ด" + ) + + def test_decimal(self): + self.assertEqual( + num2words(0.0, lang='th'), "ศูนย์" + ) + self.assertEqual( + num2words(0.0038, lang='th'), "ศูนย์จุดศูนย์ศูนย์สามแปด" + ) + self.assertEqual( + num2words(0.01, lang='th'), "ศูนย์จุดศูนย์หนึ่ง" + ) + self.assertEqual( + num2words(1.123, lang='th'), "หนึ่งจุดหนึ่งสองสาม" + ) + self.assertEqual( + num2words(35.37, lang='th'), "สามสิบห้าจุดสามเจ็ด" + ) + self.assertEqual( + num2words(1000000.01, lang='th'), "หนึ่งล้านจุดศูนย์หนึ่ง" + ) + + def test_currency(self): + self.assertEqual( + num2words(100, lang='th', to='currency', currency='THB'), + "หนึ่งร้อยบาทถ้วน" + ) + self.assertEqual( + num2words(100, lang='th', to='currency', currency='USD'), + "หนึ่งร้อยดอลลาร์" + ) + self.assertEqual( + num2words(100, lang='th', to='currency', currency='EUR'), + "หนึ่งร้อยยูโร" + ) + + def test_currency_decimal(self): + self.assertEqual( + num2words(0.00, lang='th', to='currency'), "ศูนย์บาทถ้วน" + ) + self.assertEqual( + num2words(0.05, lang='th', to='currency'), "ห้าสตางค์" + ) + self.assertEqual( + num2words(0.50, lang='th', to='currency'), "ห้าสิบสตางค์" + ) + self.assertEqual( + num2words(0.99, lang='th', to='currency'), "เก้าสิบเก้าสตางค์" + ) + self.assertEqual( + num2words(100.00, lang='th', to='currency'), "หนึ่งร้อยบาทถ้วน" + ) + self.assertEqual( + num2words(100.23, lang='th', to='currency', currency='USD'), + "หนึ่งร้อยดอลลาร์ยี่สิบสามเซนต์" + ) + self.assertEqual( + num2words(100.24, lang='th', to='currency', currency='EUR'), + "หนึ่งร้อยยูโรยี่สิบสี่เซนต์" + ) + + def test_negative(self): + self.assertEqual(num2words(-10, lang='th'), "ติดลบสิบ") + self.assertEqual(num2words(-10.50, lang='th'), "ติดลบสิบจุดห้า") + self.assertEqual( + num2words(-100.00, lang='th', to='currency'), + "ติดลบหนึ่งร้อยบาทถ้วน" + ) + + def test_round_2_decimal(self): + n2wTH = Num2Word_TH() + self.assertEqual(n2wTH.round_2_decimal(0.004), ('0.00', False)) + self.assertEqual(n2wTH.round_2_decimal(0.005), ('0.01', False)) + self.assertEqual(n2wTH.round_2_decimal(0.006), ('0.01', False)) + self.assertEqual(n2wTH.round_2_decimal(0.0005), + ('0.00', False)) + self.assertEqual(n2wTH.round_2_decimal(0.984), ('0.98', False)) + self.assertEqual(n2wTH.round_2_decimal(0.989), ('0.99', False)) + self.assertEqual(n2wTH.round_2_decimal(0.994), ('0.99', False)) + self.assertEqual(n2wTH.round_2_decimal(0.999), ('1.00', False)) + self.assertEqual(n2wTH.round_2_decimal(-0.994), ('0.99', True)) + self.assertEqual(n2wTH.round_2_decimal(-0.999), ('1.00', True)) + # self.assertEqual(n2wTH.round_2_decimal(0.985), ('0.99', False)) + # Expect 0.99 get 0.98 + # self.assertEqual(n2wTH.round_2_decimal(0.995), ('1.00', False)) + # Expect 1.00 get 0.99 + + def test_split_six(self): + n2wTH = Num2Word_TH() + self.assertEqual(n2wTH.split_six(str(123456789)), + ['987654', '321']) + self.assertEqual(n2wTH.split_six(str(12345)), + ['54321']) + self.assertEqual(n2wTH.split_six(str(1234567)), + ['765432', '1']) diff --git a/tests/test_utils.py b/tests/test_utils.py new file mode 100644 index 0000000..9352023 --- /dev/null +++ b/tests/test_utils.py @@ -0,0 +1,24 @@ +from unittest import TestCase + +from num2words.utils import splitbyx + + +class TestUtils(TestCase): + def test_splitbyx(self): + self.assertEqual(list(splitbyx(str(12), 3)), [12]) + self.assertEqual(list(splitbyx(str(1234), 3)), [1, 234]) + self.assertEqual(list(splitbyx(str(12345678900), 3)), + [12, 345, 678, 900] + ) + self.assertEqual(list(splitbyx(str(1000000), 6)), [1, 0]) + + self.assertEqual(list(splitbyx(str(12), 3, format_int=False)), ['12']) + self.assertEqual(list(splitbyx(str(1234), 3, format_int=False)), + ['1', '234'] + ) + self.assertEqual(list(splitbyx(str(12345678900), 3, format_int=False)), + ['12', '345', '678', '900'] + ) + self.assertEqual(list(splitbyx(str(1000000), 6, format_int=False)), + ['1', '000000'] + )