From 797e74d1fc342704d68be15bc69b44f408fed89e Mon Sep 17 00:00:00 2001 From: isnani Date: Sat, 12 Dec 2015 16:54:30 +0100 Subject: [PATCH 01/99] correction on lang_DE: ordnum, plural and ord form of >= 10**6 --- num2words/base.py | 1 - num2words/lang_DE.py | 45 ++++++++++++++++++++++---------------------- tests/test_de.py | 38 +++++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 23 deletions(-) create mode 100644 tests/test_de.py diff --git a/num2words/base.py b/num2words/base.py index f892d42..b094c67 100644 --- a/num2words/base.py +++ b/num2words/base.py @@ -101,7 +101,6 @@ class Num2Word_Base(object): if value >= self.MAXVAL: raise OverflowError(self.errmsg_toobig % (value, self.MAXVAL)) - val = self.splitnum(value) words, num = self.clean(val) diff --git a/num2words/lang_DE.py b/num2words/lang_DE.py index e31dc5b..62b67fb 100644 --- a/num2words/lang_DE.py +++ b/num2words/lang_DE.py @@ -26,7 +26,6 @@ class Num2Word_DE(Num2Word_EU): self.cards[10**n] = word + "illiarde" self.cards[10**(n-3)] = word + "illion" - def setup(self): self.negword = "minus " self.pointword = "Komma" @@ -49,14 +48,19 @@ class Num2Word_DE(Num2Word_EU): "zw\xF6lf", "elf", "zehn", "neun", "acht", "sieben", "sechs", "f\xFCnf", "vier", "drei", "zwei", "eins", "null"] - self.ords = { "eins" : "ers", - "drei" : "drit", - "acht" : "ach", - "sieben" : "sieb", - "ig" : "igs" } + self.ords = {"eins": "ers", + "drei": "drit", + "acht": "ach", + "sieben": "sieb", + "ig": "igs", + "ert": "erts", + "end": "ends", + "ion": "ions", + "nen": "nens", + "rde": "rdes", + "rden": "rdens"} self.ordflag = False - def merge(self, curr, next): ctext, cnum, ntext, nnum = curr + next @@ -69,41 +73,35 @@ class Num2Word_DE(Num2Word_EU): if nnum >= 10**6: if cnum > 1: if ntext.endswith("e") or self.ordflag: - ntext += "s" + ntext += "n" else: - ntext += "es" + ntext += "en" ctext += " " val = cnum * nnum else: if nnum < 10 < cnum < 100: if nnum == 1: ntext = "ein" - ntext, ctext = ctext, ntext + "und" + ntext, ctext = ctext, ntext + "und" elif cnum >= 10**6: ctext += " " val = cnum + nnum word = ctext + ntext return (word, val) - def to_ordinal(self, value): self.verify_ordinal(value) - self.ordflag = True outword = self.to_cardinal(value) - self.ordflag = False for key in self.ords: if outword.endswith(key): outword = outword[:len(outword) - len(key)] + self.ords[key] break return outword + "te" - - # Is this correct?? def to_ordinal_num(self, value): self.verify_ordinal(value) - return str(value) + "te" - + return str(value) + "." def to_currency(self, val, longval=True, old=False): if old: @@ -117,8 +115,6 @@ class Num2Word_DE(Num2Word_EU): return self.to_cardinal(val) return self.to_splitnum(val, hightxt="hundert", longval=longval) - - n2w = Num2Word_DE() to_card = n2w.to_cardinal to_ord = n2w.to_ordinal @@ -126,15 +122,20 @@ to_ordnum = n2w.to_ordinal_num def main(): - for val in [ 1, 11, 12, 21, 31, 33, 71, 80, 81, 91, 99, 100, 101, 102, 155, + for val in [1, 7, 8, 12, 17, 81, 91, 99, 100, 101, 102, 155, 180, 300, 308, 832, 1000, 1001, 1061, 1100, 1500, 1701, 3000, - 8280, 8291, 150000, 500000, 1000000, 2000000, 2000001, + 8280, 8291, 150000, 500000, 3000000, 1000000, 2000001, 1000000000, 2000000000, -21212121211221211111, -2.121212, -1.0000100]: n2w.test(val) - n2w.test(1325325436067876801768700107601001012212132143210473207540327057320957032975032975093275093275093270957329057320975093272950730) + # n2w.test(1325325436067876801768700107601001012212132143210473207540327057320957032975032975093275093275093270957329057320975093272950730) + n2w.test(3000000) + n2w.test(3000000000001) + n2w.test(3000000324566) print n2w.to_currency(112121) print n2w.to_year(2000) + print n2w.to_year(1820) + print n2w.to_year(2001) if __name__ == "__main__": main() diff --git a/tests/test_de.py b/tests/test_de.py new file mode 100644 index 0000000..c5b4402 --- /dev/null +++ b/tests/test_de.py @@ -0,0 +1,38 @@ +# -*- encoding: utf-8 -*- +# Copyright (c) 2015, 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 unittest import TestCase + +from num2words import num2words + +class Num2WordsDETest(TestCase): + def test_ordinal_less_than_twenty(self): + self.assertEqual(num2words(7, ordinal=True, lang='de'), "siebte") + self.assertEqual(num2words(8, ordinal=True, lang='de'), "achte") + self.assertEqual(num2words(12, ordinal=True, lang='de'), "zwölfte") + self.assertEqual(num2words(17, ordinal=True, lang='de'), "siebzehnte") + + def test_ordinal_more_than_twenty(self): + self.assertEqual(num2words(81, ordinal=True, lang='de'), "einundachtzigste") + + def test_ordinal_at_crucial_number(self): + self.assertEqual(num2words(100, ordinal=True, lang='de'), "hundertste") + self.assertEqual(num2words(1000, ordinal=True, lang='de'), "tausendste") + self.assertEqual(num2words(4000, ordinal=True, lang='de'), "viertausendste") + self.assertEqual(num2words(2000000, ordinal=True, lang='de'), "zwei millionenste") + self.assertEqual(num2words(5000000000, ordinal=True, lang='de'), "fünf milliardenste") \ No newline at end of file From 41a97d693194904fc7f556949572c8da1bda594b Mon Sep 17 00:00:00 2001 From: isnani Date: Mon, 14 Dec 2015 08:26:08 +0100 Subject: [PATCH 02/99] add tests for lang_DE --- tests/test_de.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/tests/test_de.py b/tests/test_de.py index c5b4402..98e34f2 100644 --- a/tests/test_de.py +++ b/tests/test_de.py @@ -35,4 +35,17 @@ class Num2WordsDETest(TestCase): self.assertEqual(num2words(1000, ordinal=True, lang='de'), "tausendste") self.assertEqual(num2words(4000, ordinal=True, lang='de'), "viertausendste") self.assertEqual(num2words(2000000, ordinal=True, lang='de'), "zwei millionenste") - self.assertEqual(num2words(5000000000, ordinal=True, lang='de'), "fünf milliardenste") \ No newline at end of file + self.assertEqual(num2words(5000000000, ordinal=True, lang='de'), "fünf milliardenste") + + def test_cardinal_at_some_numbers(self): + self.assertEqual(num2words(2000000, lang='de'), "zwei millionen") + self.assertEqual(num2words(4000000000, lang='de'), "vier milliarden") + + def test_cardinal_for_decimal_number(self): + self.assertEqual(num2words(3.486, lang='de'), "drei Komma vier acht") + + def test_ordinal_for_negative_numbers(self): + self.assertRaises(TypeError, num2words, -12, ordinal=True, lang='de') + + def test_ordinal_for_floating_numbers(self): + self.assertRaises(TypeError, num2words, 2.453, ordinal=True, lang='de') \ No newline at end of file From 9d99647e17ef1f2e3e521393a9bbd4b0bc7cdbe6 Mon Sep 17 00:00:00 2001 From: isnani Date: Mon, 14 Dec 2015 08:40:32 +0100 Subject: [PATCH 03/99] remove unnecessary self.ordflag --- num2words/lang_DE.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/num2words/lang_DE.py b/num2words/lang_DE.py index 62b67fb..c9f73eb 100644 --- a/num2words/lang_DE.py +++ b/num2words/lang_DE.py @@ -59,20 +59,19 @@ class Num2Word_DE(Num2Word_EU): "nen": "nens", "rde": "rdes", "rden": "rdens"} - self.ordflag = False def merge(self, curr, next): ctext, cnum, ntext, nnum = curr + next if cnum == 1: - if nnum < 10**6 or self.ordflag: + if nnum < 10**6: return next ctext = "eine" if nnum > cnum: if nnum >= 10**6: if cnum > 1: - if ntext.endswith("e") or self.ordflag: + if ntext.endswith("e"): ntext += "n" else: ntext += "en" From 01b87602c8b30bc8365ee0c0dbaba6f0bde9bcdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98rjan=20V=C3=B8llestad?= Date: Mon, 11 Jan 2016 19:33:22 +0100 Subject: [PATCH 04/99] added norwegian support --- num2words/__init__.py | 2 + num2words/lang_NO.py | 121 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 num2words/lang_NO.py diff --git a/num2words/__init__.py b/num2words/__init__.py index 1a753ce..10fd631 100644 --- a/num2words/__init__.py +++ b/num2words/__init__.py @@ -25,6 +25,7 @@ from . import lang_ES from . import lang_LT from . import lang_LV from . import lang_PL +from . import lang_NO CONVERTER_CLASSES = { 'en': lang_EN.Num2Word_EN(), @@ -36,6 +37,7 @@ CONVERTER_CLASSES = { 'lt': lang_LT.Num2Word_LT(), 'lv': lang_LV.Num2Word_LV(), 'pl': lang_PL.Num2Word_PL(), + 'no': lang_NO.Num2Word_NO(), } def num2words(number, ordinal=False, lang='en'): diff --git a/num2words/lang_NO.py b/num2words/lang_NO.py new file mode 100644 index 0000000..273622b --- /dev/null +++ b/num2words/lang_NO.py @@ -0,0 +1,121 @@ +# Copyright (c) 2003, Taro Ogawa. All Rights Reserved. +# Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. + +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301 USA + +from __future__ import division, unicode_literals +from . import lang_EU + +class Num2Word_NO(lang_EU.Num2Word_EU): + def set_high_numwords(self, high): + max = 3 + 6*len(high) + for word, n in zip(high, range(max, 3, -6)): + self.cards[10**n] = word + "illard" + self.cards[10**(n-3)] = word + "illion" + + def setup(self): + self.negword = "minus " + self.pointword = "komma" + self.errmsg_nornum = "Bare tall kan bli konvertert til ord." + self.exclude_title = ["og", "komma", "minus"] + + self.mid_numwords = [(1000, "tusen"), (100, "hundre"), + (90, "nitti"), (80, "\xe5tti"), (70, "sytti"), + (60, "seksti"), (50, "femti"), (40, "f\xf8rti"), + (30, "tretti")] + self.low_numwords = ["tjue", "nitten", "atten", "sytten", + "seksten", "femten", "fjorten", "tretten", + "tolv", "elleve", "ti", "ni", "\xe5tte", + "syv", "seks", "fem", "fire", "tre", "to", + "en", "null"] + self.ords = { "en" : "f\xf8rste", + "to" : "andre", + "tre" : "tredje", + "fire" : "fjerde", + "fem" : "femte", + "seks" : "sjette", + "syv" : "syvende", + "\xe5tte" : "\xe5ttende", + "ni" : "niende", + "ti" : "tiende", + "elleve" : "ellevte", + "tolv" : "tolvte", + "tjue" : "tjuende" } + + + def merge(self, (ltext, lnum), (rtext, rnum)): + if lnum == 1 and rnum < 100: + return (rtext, rnum) + elif 100 > lnum > rnum : + return ("%s-%s"%(ltext, rtext), lnum + rnum) + elif lnum >= 100 > rnum: + return ("%s og %s"%(ltext, rtext), lnum + rnum) + elif rnum > lnum: + return ("%s %s"%(ltext, rtext), lnum * rnum) + return ("%s, %s"%(ltext, rtext), lnum + rnum) + + + def to_ordinal(self, value): + self.verify_ordinal(value) + outwords = self.to_cardinal(value).split(" ") + lastwords = outwords[-1].split("-") + lastword = lastwords[-1].lower() + try: + lastword = self.ords[lastword] + except KeyError: + if lastword[-2:] == "ti": + lastword = lastword + "ende" + else: + lastword += "de" + lastwords[-1] = self.title(lastword) + outwords[-1] = "".join(lastwords) + return " ".join(outwords) + + + def to_ordinal_num(self, value): + self.verify_ordinal(value) + return "%s%s"%(value, self.to_ordinal(value)[-2:]) + + + def to_year(self, val, longval=True): + if not (val//100)%10: + return self.to_cardinal(val) + return self.to_splitnum(val, hightxt="hundre", jointxt="og", + longval=longval) + + def to_currency(self, val, longval=True): + return self.to_splitnum(val, hightxt="krone/r", lowtxt="\xf8re/r", + jointxt="og", longval=longval, cents = True) + + +n2w = Num2Word_NO() +to_card = n2w.to_cardinal +to_ord = n2w.to_ordinal +to_ordnum = n2w.to_ordinal_num +to_year = n2w.to_year + +def main(): + for val in [ 1, 11, 12, 21, 31, 33, 71, 80, 81, 91, 99, 100, 101, 102, 155, + 180, 300, 308, 832, 1000, 1001, 1061, 1100, 1500, 1701, 3000, + 8280, 8291, 150000, 500000, 1000000, 2000000, 2000001, + -21212121211221211111, -2.121212, -1.0000100]: + n2w.test(val) + n2w.test(1325325436067876801768700107601001012212132143210473207540327057320957032975032975093275093275093270957329057320975093272950730) + for val in [1,120,1000,1120,1800, 1976,2000,2010,2099,2171]: + print val, "er", n2w.to_currency(val) + print val, "er", n2w.to_year(val) + + +if __name__ == "__main__": + main() From 1589d9bb79fa8aa0c3a784f557db92112bf615ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98rjan=20V=C3=B8llestad?= Date: Mon, 11 Jan 2016 19:35:11 +0100 Subject: [PATCH 05/99] added norwegian support --- README.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/README.rst b/README.rst index 986ff86..f062e9f 100644 --- a/README.rst +++ b/README.rst @@ -49,6 +49,7 @@ Besides the numerical argument, there's two optional arguments. * ``lv`` (Latvian) * ``en_GB`` (British English) * ``en_IN`` (Indian English) +* ``no`` (Norwegian) * ``pl`` (Polish) You can supply values like ``fr_FR``, the code will be From 073925b1d4128da1352a4f908aa2c19402ceb640 Mon Sep 17 00:00:00 2001 From: isnani Date: Fri, 18 Dec 2015 05:36:01 +0100 Subject: [PATCH 06/99] address issue 24: floating point spelling --- num2words/base.py | 7 +++---- tests/test_en.py | 7 +++++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/num2words/base.py b/num2words/base.py index f892d42..960817a 100644 --- a/num2words/base.py +++ b/num2words/base.py @@ -116,16 +116,15 @@ class Num2Word_Base(object): pre = int(value) post = abs(value - pre) + post *= 10**self.precision out = [self.to_cardinal(pre)] if self.precision: out.append(self.title(self.pointword)) for i in range(self.precision): - post *= 10 - curr = int(post) - out.append(str(self.to_cardinal(curr))) - post -= curr + curr = str(post)[i] + out.append(str(self.to_cardinal(int(curr)))) return " ".join(out) diff --git a/tests/test_en.py b/tests/test_en.py index 20eb294..7897e82 100644 --- a/tests/test_en.py +++ b/tests/test_en.py @@ -21,3 +21,10 @@ class Num2WordsENTest(TestCase): def test_and_join_199(self): # ref https://github.com/savoirfairelinux/num2words/issues/8 self.assertEqual(num2words(199), "one hundred and ninety-nine") + + def test_cardinal_for_float_number(self): + # issue 24 + self.assertEqual(num2words(12.50), "twelve point five zero") + self.assertEqual(num2words(12.51), "twelve point five one") + self.assertEqual(num2words(12.53), "twelve point five three") + self.assertEqual(num2words(12.59), "twelve point five nine") \ No newline at end of file From 3d1b8ae42ce61da046df96d096cf3e8e0e630a22 Mon Sep 17 00:00:00 2001 From: Michael Reschke Date: Wed, 24 Feb 2016 19:14:22 +0100 Subject: [PATCH 07/99] Update README.rst --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 986ff86..96d41c3 100644 --- a/README.rst +++ b/README.rst @@ -63,7 +63,7 @@ Therefore, if you want to call ``num2words`` with a fallback, you can do:: History ------- -``num2words`` is based on an old library , ``pynum2word`` created by Taro Ogawa in 2003. +``num2words`` is based on an old library, ``pynum2word`` created by Taro Ogawa in 2003. Unfortunately, the library stopped being maintained and the author can't be reached. There was another developer, Marius Grigaitis, who in 2011 added Lithuanian support, but didn't take over maintenance of the project. From eeadcc7d5b1d04113d46a30c39db3628e5697667 Mon Sep 17 00:00:00 2001 From: Filipe Waitman Date: Fri, 26 Feb 2016 23:13:40 -0300 Subject: [PATCH 08/99] Add support to pt_BR language --- num2words/__init__.py | 2 + num2words/base.py | 14 +-- num2words/lang_PT_BR.py | 209 ++++++++++++++++++++++++++++++++++++++ tests/test_pt_BR.py | 219 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 437 insertions(+), 7 deletions(-) create mode 100644 num2words/lang_PT_BR.py create mode 100644 tests/test_pt_BR.py diff --git a/num2words/__init__.py b/num2words/__init__.py index 1a753ce..520b34c 100644 --- a/num2words/__init__.py +++ b/num2words/__init__.py @@ -25,6 +25,7 @@ from . import lang_ES from . import lang_LT from . import lang_LV from . import lang_PL +from . import lang_PT_BR CONVERTER_CLASSES = { 'en': lang_EN.Num2Word_EN(), @@ -36,6 +37,7 @@ CONVERTER_CLASSES = { 'lt': lang_LT.Num2Word_LT(), 'lv': lang_LV.Num2Word_LV(), 'pl': lang_PL.Num2Word_PL(), + 'pt_BR': lang_PT_BR.Num2Word_PT_BR(), } def num2words(number, ordinal=False, lang='en'): diff --git a/num2words/base.py b/num2words/base.py index f892d42..e1327ba 100644 --- a/num2words/base.py +++ b/num2words/base.py @@ -36,7 +36,7 @@ class Num2Word_Base(object): self.set_numwords() self.MAXVAL = 1000 * self.cards.order[0] - + def set_numwords(self): self.set_high_numwords(self.high_numwords) @@ -64,7 +64,7 @@ class Num2Word_Base(object): for elem in self.cards: if elem > value: continue - + out = [] if value == 0: div, mod = 1, 0 @@ -75,7 +75,7 @@ class Num2Word_Base(object): out.append((self.cards[1], 1)) else: if div == value: # The system tallies, eg Roman Numerals - return [(div * self.cards[elem], div*elem)] + return [(div * self.cards[elem], div*elem)] out.append(self.splitnum(div)) out.append((self.cards[elem], elem)) @@ -101,7 +101,7 @@ class Num2Word_Base(object): if value >= self.MAXVAL: raise OverflowError(self.errmsg_toobig % (value, self.MAXVAL)) - + val = self.splitnum(value) words, num = self.clean(val) @@ -124,7 +124,7 @@ class Num2Word_Base(object): for i in range(self.precision): post *= 10 curr = int(post) - out.append(str(self.to_cardinal(curr))) + out.append(self.to_cardinal(curr)) post -= curr return " ".join(out) @@ -183,7 +183,7 @@ class Num2Word_Base(object): def set_wordnums(self): pass - + def to_ordinal(value): return self.to_cardinal(value) @@ -260,6 +260,6 @@ class Num2Word_Base(object): _ordnum = self.to_ordinal_num(value) except: _ordnum = "invalid" - + print ("For %s, card is %s;\n\tord is %s; and\n\tordnum is %s." % (value, _card, _ord, _ordnum)) diff --git a/num2words/lang_PT_BR.py b/num2words/lang_PT_BR.py new file mode 100644 index 0000000..bf4a8f3 --- /dev/null +++ b/num2words/lang_PT_BR.py @@ -0,0 +1,209 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2003, Taro Ogawa. All Rights Reserved. +# Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. + +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301 USA + +from __future__ import division, unicode_literals +import re + +from . import lang_EU + + +class Num2Word_PT_BR(lang_EU.Num2Word_EU): + def set_high_numwords(self, high): + max = 3 + 3*len(high) + for word, n in zip(high, range(max, 3, -3)): + self.cards[10**n] = word + "ilhão" + + def setup(self): + self.negword = "menos " + self.pointword = "ponto" + self.errmsg_nornum = "Somente números podem ser convertidos para palavras" + self.exclude_title = ["e", "ponto", "menos"] + + self.mid_numwords = [ + (1000, "mil"), (100, "cem"), (90, "noventa"), + (80, "oitenta"), (70, "setenta"), (60, "sessenta"), (50, "cinquenta"), + (40, "quarenta"), (30, "trinta") + ] + self.low_numwords = [ + "vinte", "dezenove", "dezoito", "dezessete", "dezesseis", + "quinze", "catorze", "treze", "doze", "onze", "dez", + "nove", "oito", "sete", "seis", "cinco", "quatro", "três", "dois", + "um", "zero" + ] + self.ords = [ + { + 0: "", + 1: "primeiro", + 2: "segundo", + 3: "terceiro", + 4: "quarto", + 5: "quinto", + 6: "sexto", + 7: "sétimo", + 8: "oitavo", + 9: "nono", + }, + { + 0: "", + 1: "décimo", + 2: "vigésimo", + 3: "trigésimo", + 4: "quadragésimo", + 5: "quinquagésimo", + 6: "sexagésimo", + 7: "septuagésimo", + 8: "octogésimo", + 9: "nonagésimo", + }, + { + 0: "", + 1: "centésimo", + 2: "ducentésimo", + 3: "tricentésimo", + 4: "quadrigentésimo", + 5: "quingentésimo", + 6: "seiscentésimo", + 7: "septigentésimo", + 8: "octigentésimo", + 9: "nongentésimo", + }, + ] + self.thousand_separators = { + 3: "milésimo", + 6: "milionésimo", + 9: "bilionésimo", + 12: "trilionésimo", + 15: "quadrilionésimo" + } + self.hundreds = { + 1: "cento", + 2: "duzentos", + 3: "trezentos", + 4: "quatrocentos", + 5: "quinhentos", + 6: "seiscentos", + 7: "setecentos", + 8: "oitocentos", + 9: "novecentos", + } + + def merge(self, curr, next): + ctext, cnum, ntext, nnum = curr + next + + if cnum == 1: + if nnum < 1000000: + return next + ctext = "um" + elif cnum == 100 and not nnum == 1000: + ctext = "cento" + + if nnum < cnum: + if cnum < 100: + return ("%s e %s" % (ctext, ntext), cnum + nnum) + return ("%s e %s" % (ctext, ntext), cnum + nnum) + + elif (not nnum % 1000000) and cnum > 1: + ntext = ntext[:-4] + "lhões" + + if nnum == 100: + ctext = self.hundreds[cnum] + ntext = "" + + else: + ntext = " " + ntext + + return (ctext + ntext, cnum * nnum) + + def to_cardinal(self, value): + result = super(Num2Word_PT_BR, self).to_cardinal(value) + + # Transforms "mil E cento e catorze reais" into "mil, cento e catorze reais" + for ext in ( + 'mil', 'milhão', 'milhões', 'bilhão', 'bilhões', + 'trilhão', 'trilhões', 'quatrilhão', 'quatrilhões'): + if re.match('.*{} e \w*ento'.format(ext), result): + result = result.replace('{} e'.format(ext), '{},'.format(ext), 1) + + return result + + def to_ordinal(self, value): + self.verify_ordinal(value) + + result = [] + value = str(value) + thousand_separator = '' + + for idx, char in enumerate(value[::-1]): + if idx and idx % 3 == 0: + thousand_separator = self.thousand_separators[idx] + + if char != '0' and thousand_separator: + # avoiding "segundo milionésimo milésimo" for 6000000, for instance + result.append(thousand_separator) + thousand_separator = '' + + result.append(self.ords[idx % 3][int(char)]) + + result = ' '.join(result[::-1]) + result = result.strip() + result = re.sub('\s+', ' ', result) + + if result.startswith('primeiro') and value != '1': + # avoiding "primeiro milésimo", "primeiro milionésimo" and so on + result = result[9:] + + return result + + def to_ordinal_num(self, value): + self.verify_ordinal(value) + return "%sº" % (value) + + def to_year(self, val, longval=True): + if val < 0: + return self.to_cardinal(abs(val)) + ' antes de Cristo' + return self.to_cardinal(val) + + def to_currency(self, val, longval=True): + integer_part, decimal_part = ('%.2f' % val).split('.') + + result = self.to_cardinal(int(integer_part)) + + appended_currency = False + for ext in ( + 'milhão', 'milhões', 'bilhão', 'bilhões', + 'trilhão', 'trilhões', 'quatrilhão', 'quatrilhões'): + if result.endswith(ext): + result += ' de reais' + appended_currency = True + + if result in ['um', 'menos um']: + result += ' real' + appended_currency = True + if not appended_currency: + result += ' reais' + + if int(decimal_part): + cents = self.to_cardinal(int(decimal_part)) + result += ' e ' + cents + + if cents == 'um': + result += ' centavo' + else: + result += ' centavos' + + return result diff --git a/tests/test_pt_BR.py b/tests/test_pt_BR.py new file mode 100644 index 0000000..d2f4b22 --- /dev/null +++ b/tests/test_pt_BR.py @@ -0,0 +1,219 @@ +# -*- encoding: utf-8 -*- +# Copyright (c) 2015, 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 decimal import Decimal +from unittest import TestCase + +from num2words import num2words +from num2words.lang_PT_BR import Num2Word_PT_BR + + +class Num2WordsPTBRTest(TestCase): + def setUp(self): + super(Num2WordsPTBRTest, self).setUp() + self.n2w = Num2Word_PT_BR() + + def test_cardinal_integer(self): + self.assertEquals(num2words(1, lang='pt_BR'), 'um') + self.assertEquals(num2words(2, lang='pt_BR'), 'dois') + self.assertEquals(num2words(3, lang='pt_BR'), 'três') + self.assertEquals(num2words(4, lang='pt_BR'), 'quatro') + self.assertEquals(num2words(5, lang='pt_BR'), 'cinco') + self.assertEquals(num2words(6, lang='pt_BR'), 'seis') + self.assertEquals(num2words(7, lang='pt_BR'), 'sete') + self.assertEquals(num2words(8, lang='pt_BR'), 'oito') + self.assertEquals(num2words(9, lang='pt_BR'), 'nove') + self.assertEquals(num2words(10, lang='pt_BR'), 'dez') + self.assertEquals(num2words(11, lang='pt_BR'), 'onze') + self.assertEquals(num2words(12, lang='pt_BR'), 'doze') + self.assertEquals(num2words(13, lang='pt_BR'), 'treze') + self.assertEquals(num2words(14, lang='pt_BR'), 'catorze') + self.assertEquals(num2words(15, lang='pt_BR'), 'quinze') + self.assertEquals(num2words(16, lang='pt_BR'), 'dezesseis') + self.assertEquals(num2words(17, lang='pt_BR'), 'dezessete') + self.assertEquals(num2words(18, lang='pt_BR'), 'dezoito') + self.assertEquals(num2words(19, lang='pt_BR'), 'dezenove') + self.assertEquals(num2words(20, lang='pt_BR'), 'vinte') + + self.assertEquals(num2words(21, lang='pt_BR'), 'vinte e um') + self.assertEquals(num2words(22, lang='pt_BR'), 'vinte e dois') + self.assertEquals(num2words(35, lang='pt_BR'), 'trinta e cinco') + self.assertEquals(num2words(99, lang='pt_BR'), 'noventa e nove') + + self.assertEquals(num2words(100, lang='pt_BR'), 'cem') + self.assertEquals(num2words(101, lang='pt_BR'), 'cento e um') + self.assertEquals(num2words(128, lang='pt_BR'), 'cento e vinte e oito') + self.assertEquals(num2words(713, lang='pt_BR'), 'setecentos e treze') + + self.assertEquals(num2words(1000, lang='pt_BR'), 'mil') + self.assertEquals(num2words(1001, lang='pt_BR'), 'mil e um') + self.assertEquals(num2words(1111, lang='pt_BR'), 'mil, cento e onze') + self.assertEquals(num2words(2114, lang='pt_BR'), 'dois mil, cento e catorze') + self.assertEquals(num2words(73421, lang='pt_BR'), 'setenta e três mil, quatrocentos e vinte e um') + + self.assertEquals(num2words(100000, lang='pt_BR'), 'cem mil') + self.assertEquals(num2words(250050, lang='pt_BR'), 'duzentos e cinquenta mil e cinquenta') + self.assertEquals(num2words(6000000, lang='pt_BR'), 'seis milhões') + self.assertEquals(num2words(19000000000, lang='pt_BR'), 'dezenove bilhões') + self.assertEquals(num2words(145000000002, lang='pt_BR'), 'cento e quarenta e cinco bilhões e dois') + + def test_cardinal_integer_negative(self): + self.assertEquals(num2words(-1, lang='pt_BR'), 'menos um') + self.assertEquals(num2words(-256, lang='pt_BR'), 'menos duzentos e cinquenta e seis') + self.assertEquals(num2words(-1000, lang='pt_BR'), 'menos mil') + self.assertEquals(num2words(-1000000, lang='pt_BR'), 'menos um milhão') + self.assertEquals(num2words(-1234567, lang='pt_BR'), 'menos um milhão, duzentos e trinta e quatro mil, quinhentos e sessenta e sete') + + def test_cardinal_float(self): + self.assertEquals(num2words(Decimal('1.00'), lang='pt_BR'), 'um') + self.assertEquals(num2words(Decimal('1.01'), lang='pt_BR'), 'um ponto zero um') + self.assertEquals(num2words(Decimal('1.035'), lang='pt_BR'), 'um ponto zero três') + self.assertEquals(num2words(Decimal('1.35'), lang='pt_BR'), 'um ponto três cinco') + self.assertEquals(num2words(Decimal('3.14159'), lang='pt_BR'), 'três ponto um quatro') + self.assertEquals(num2words(Decimal('101.22'), lang='pt_BR'), 'cento e um ponto dois dois') + self.assertEquals(num2words(Decimal('2345.75'), lang='pt_BR'), 'dois mil, trezentos e quarenta e cinco ponto sete cinco') + + def test_cardinal_float_negative(self): + self.assertEquals(num2words(Decimal('-2.34'), lang='pt_BR'), 'menos dois ponto três quatro') + self.assertEquals(num2words(Decimal('-9.99'), lang='pt_BR'), 'menos nove ponto nove nove') + self.assertEquals(num2words(Decimal('-7.01'), lang='pt_BR'), 'menos sete ponto zero um') + self.assertEquals(num2words(Decimal('-222.22'), lang='pt_BR'), 'menos duzentos e vinte e dois ponto dois dois') + + def test_ordinal(self): + self.assertEquals(num2words(1, lang='pt_BR', ordinal=True), 'primeiro') + self.assertEquals(num2words(2, lang='pt_BR', ordinal=True), 'segundo') + self.assertEquals(num2words(3, lang='pt_BR', ordinal=True), 'terceiro') + self.assertEquals(num2words(4, lang='pt_BR', ordinal=True), 'quarto') + self.assertEquals(num2words(5, lang='pt_BR', ordinal=True), 'quinto') + self.assertEquals(num2words(6, lang='pt_BR', ordinal=True), 'sexto') + self.assertEquals(num2words(7, lang='pt_BR', ordinal=True), 'sétimo') + self.assertEquals(num2words(8, lang='pt_BR', ordinal=True), 'oitavo') + self.assertEquals(num2words(9, lang='pt_BR', ordinal=True), 'nono') + self.assertEquals(num2words(10, lang='pt_BR', ordinal=True), 'décimo') + self.assertEquals(num2words(11, lang='pt_BR', ordinal=True), 'décimo primeiro') + self.assertEquals(num2words(12, lang='pt_BR', ordinal=True), 'décimo segundo') + self.assertEquals(num2words(13, lang='pt_BR', ordinal=True), 'décimo terceiro') + self.assertEquals(num2words(14, lang='pt_BR', ordinal=True), 'décimo quarto') + self.assertEquals(num2words(15, lang='pt_BR', ordinal=True), 'décimo quinto') + self.assertEquals(num2words(16, lang='pt_BR', ordinal=True), 'décimo sexto') + self.assertEquals(num2words(17, lang='pt_BR', ordinal=True), 'décimo sétimo') + self.assertEquals(num2words(18, lang='pt_BR', ordinal=True), 'décimo oitavo') + self.assertEquals(num2words(19, lang='pt_BR', ordinal=True), 'décimo nono') + self.assertEquals(num2words(20, lang='pt_BR', ordinal=True), 'vigésimo') + + self.assertEquals(num2words(21, lang='pt_BR', ordinal=True), 'vigésimo primeiro') + self.assertEquals(num2words(22, lang='pt_BR', ordinal=True), 'vigésimo segundo') + self.assertEquals(num2words(35, lang='pt_BR', ordinal=True), 'trigésimo quinto') + self.assertEquals(num2words(99, lang='pt_BR', ordinal=True), 'nonagésimo nono') + + self.assertEquals(num2words(100, lang='pt_BR', ordinal=True), 'centésimo') + self.assertEquals(num2words(101, lang='pt_BR', ordinal=True), 'centésimo primeiro') + self.assertEquals(num2words(128, lang='pt_BR', ordinal=True), 'centésimo vigésimo oitavo') + self.assertEquals(num2words(713, lang='pt_BR', ordinal=True), 'septigentésimo décimo terceiro') + + self.assertEquals(num2words(1000, lang='pt_BR', ordinal=True), 'milésimo') + self.assertEquals(num2words(1001, lang='pt_BR', ordinal=True), 'milésimo primeiro') + self.assertEquals(num2words(1111, lang='pt_BR', ordinal=True), 'milésimo centésimo décimo primeiro') + self.assertEquals(num2words(2114, lang='pt_BR', ordinal=True), 'segundo milésimo centésimo décimo quarto') + self.assertEquals(num2words(73421, lang='pt_BR', ordinal=True), 'septuagésimo terceiro milésimo quadrigentésimo vigésimo primeiro') + + self.assertEquals(num2words(100000, lang='pt_BR', ordinal=True), 'centésimo milésimo') + self.assertEquals(num2words(250050, lang='pt_BR', ordinal=True), 'ducentésimo quinquagésimo milésimo quinquagésimo') + self.assertEquals(num2words(6000000, lang='pt_BR', ordinal=True), 'sexto milionésimo') + self.assertEquals(num2words(19000000000, lang='pt_BR', ordinal=True), 'décimo nono bilionésimo') + self.assertEquals(num2words(145000000002, lang='pt_BR', ordinal=True), 'centésimo quadragésimo quinto bilionésimo segundo') + + def test_currency_integer(self): + self.assertEquals(self.n2w.to_currency(1), 'um real') + self.assertEquals(self.n2w.to_currency(2), 'dois reais') + self.assertEquals(self.n2w.to_currency(3), 'três reais') + self.assertEquals(self.n2w.to_currency(4), 'quatro reais') + self.assertEquals(self.n2w.to_currency(5), 'cinco reais') + self.assertEquals(self.n2w.to_currency(6), 'seis reais') + self.assertEquals(self.n2w.to_currency(7), 'sete reais') + self.assertEquals(self.n2w.to_currency(8), 'oito reais') + self.assertEquals(self.n2w.to_currency(9), 'nove reais') + self.assertEquals(self.n2w.to_currency(10), 'dez reais') + self.assertEquals(self.n2w.to_currency(11), 'onze reais') + self.assertEquals(self.n2w.to_currency(12), 'doze reais') + self.assertEquals(self.n2w.to_currency(13), 'treze reais') + self.assertEquals(self.n2w.to_currency(14), 'catorze reais') + self.assertEquals(self.n2w.to_currency(15), 'quinze reais') + self.assertEquals(self.n2w.to_currency(16), 'dezesseis reais') + self.assertEquals(self.n2w.to_currency(17), 'dezessete reais') + self.assertEquals(self.n2w.to_currency(18), 'dezoito reais') + self.assertEquals(self.n2w.to_currency(19), 'dezenove reais') + self.assertEquals(self.n2w.to_currency(20), 'vinte reais') + + self.assertEquals(self.n2w.to_currency(21), 'vinte e um reais') + self.assertEquals(self.n2w.to_currency(22), 'vinte e dois reais') + self.assertEquals(self.n2w.to_currency(35), 'trinta e cinco reais') + self.assertEquals(self.n2w.to_currency(99), 'noventa e nove reais') + + self.assertEquals(self.n2w.to_currency(100), 'cem reais') + self.assertEquals(self.n2w.to_currency(101), 'cento e um reais') + self.assertEquals(self.n2w.to_currency(128), 'cento e vinte e oito reais') + self.assertEquals(self.n2w.to_currency(713), 'setecentos e treze reais') + + self.assertEquals(self.n2w.to_currency(1000), 'mil reais') + self.assertEquals(self.n2w.to_currency(1001), 'mil e um reais') + self.assertEquals(self.n2w.to_currency(1111), 'mil, cento e onze reais') + self.assertEquals(self.n2w.to_currency(2114), 'dois mil, cento e catorze reais') + self.assertEquals(self.n2w.to_currency(73421), 'setenta e três mil, quatrocentos e vinte e um reais') + + self.assertEquals(self.n2w.to_currency(100000), 'cem mil reais') + self.assertEquals(self.n2w.to_currency(250050), 'duzentos e cinquenta mil e cinquenta reais') + self.assertEquals(self.n2w.to_currency(6000000), 'seis milhões de reais') + self.assertEquals(self.n2w.to_currency(19000000000), 'dezenove bilhões de reais') + self.assertEquals(self.n2w.to_currency(145000000002), 'cento e quarenta e cinco bilhões e dois reais') + + def test_currency_integer_negative(self): + self.assertEquals(self.n2w.to_currency(-1), 'menos um real') + self.assertEquals(self.n2w.to_currency(-256), 'menos duzentos e cinquenta e seis reais') + self.assertEquals(self.n2w.to_currency(-1000), 'menos mil reais') + self.assertEquals(self.n2w.to_currency(-1000000), 'menos um milhão de reais') + self.assertEquals(self.n2w.to_currency(-1234567), 'menos um milhão, duzentos e trinta e quatro mil, quinhentos e sessenta e sete reais') + + def test_currency_float(self): + self.assertEquals(self.n2w.to_currency(Decimal('1.00')), 'um real') + self.assertEquals(self.n2w.to_currency(Decimal('1.01')), 'um real e um centavo') + self.assertEquals(self.n2w.to_currency(Decimal('1.035')), 'um real e três centavos') + self.assertEquals(self.n2w.to_currency(Decimal('1.35')), 'um real e trinta e cinco centavos') + self.assertEquals(self.n2w.to_currency(Decimal('3.14159')), 'três reais e catorze centavos') + self.assertEquals(self.n2w.to_currency(Decimal('101.22')), 'cento e um reais e vinte e dois centavos') + self.assertEquals(self.n2w.to_currency(Decimal('2345.75')), 'dois mil, trezentos e quarenta e cinco reais e setenta e cinco centavos') + + def test_currency_float_negative(self): + self.assertEquals(self.n2w.to_currency(Decimal('-2.34')), 'menos dois reais e trinta e quatro centavos') + self.assertEquals(self.n2w.to_currency(Decimal('-9.99')), 'menos nove reais e noventa e nove centavos') + self.assertEquals(self.n2w.to_currency(Decimal('-7.01')), 'menos sete reais e um centavo') + self.assertEquals(self.n2w.to_currency(Decimal('-222.22')), 'menos duzentos e vinte e dois reais e vinte e dois centavos') + + def test_year(self): + self.assertEquals(self.n2w.to_year(1001), 'mil e um') + self.assertEquals(self.n2w.to_year(1789), 'mil, setecentos e oitenta e nove') + self.assertEquals(self.n2w.to_year(1942), 'mil, novecentos e quarenta e dois') + self.assertEquals(self.n2w.to_year(1984), 'mil, novecentos e oitenta e quatro') + self.assertEquals(self.n2w.to_year(2000), 'dois mil') + self.assertEquals(self.n2w.to_year(2001), 'dois mil e um') + self.assertEquals(self.n2w.to_year(2016), 'dois mil e dezesseis') + + def test_year_negative(self): + self.assertEquals(self.n2w.to_year(-30), 'trinta antes de Cristo') + self.assertEquals(self.n2w.to_year(-744), 'setecentos e quarenta e quatro antes de Cristo') + self.assertEquals(self.n2w.to_year(-10000), 'dez mil antes de Cristo') From 17cf62729e9c98cbe207158bb4fdff66909fbc13 Mon Sep 17 00:00:00 2001 From: Filipe Waitman Date: Sat, 27 Feb 2016 12:36:33 -0300 Subject: [PATCH 09/99] Update README.rst --- README.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/README.rst b/README.rst index 986ff86..7401325 100644 --- a/README.rst +++ b/README.rst @@ -50,6 +50,7 @@ Besides the numerical argument, there's two optional arguments. * ``en_GB`` (British English) * ``en_IN`` (Indian English) * ``pl`` (Polish) +* ``pt_BR`` (Brazilian Portuguese) You can supply values like ``fr_FR``, the code will be correctly interpreted. If you supply an unsupported language, ``NotImplementedError`` is raised. From e8bcc0ef2d78fec6a9f72ecb84ba8d6accd9e400 Mon Sep 17 00:00:00 2001 From: Brett Anthoine Date: Fri, 18 Mar 2016 15:52:30 +0100 Subject: [PATCH 10/99] Add Swiss-French variants of numbers between 60 and 100. --- num2words/__init__.py | 2 + num2words/lang_FR_CH.py | 113 ++++++++++++++++++++++++++++++++++++++++ tests/test_fr_ch.py | 36 +++++++++++++ 3 files changed, 151 insertions(+) create mode 100644 num2words/lang_FR_CH.py create mode 100644 tests/test_fr_ch.py diff --git a/num2words/__init__.py b/num2words/__init__.py index 1a753ce..220f0c3 100644 --- a/num2words/__init__.py +++ b/num2words/__init__.py @@ -20,6 +20,7 @@ from . import lang_EN from . import lang_EN_GB from . import lang_EN_IN from . import lang_FR +from . import lang_FR_CH from . import lang_DE from . import lang_ES from . import lang_LT @@ -31,6 +32,7 @@ CONVERTER_CLASSES = { 'en_GB': lang_EN_GB.Num2Word_EN_GB(), 'en_IN': lang_EN_IN.Num2Word_EN_IN(), 'fr': lang_FR.Num2Word_FR(), + 'fr_CH': lang_FR_CH.Num2Word_FR_CH(), 'de': lang_DE.Num2Word_DE(), 'es': lang_ES.Num2Word_ES(), 'lt': lang_LT.Num2Word_LT(), diff --git a/num2words/lang_FR_CH.py b/num2words/lang_FR_CH.py new file mode 100644 index 0000000..127037d --- /dev/null +++ b/num2words/lang_FR_CH.py @@ -0,0 +1,113 @@ +# -*- 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 .lang_EU import Num2Word_EU + +class Num2Word_FR_CH(Num2Word_EU): + def setup(self): + self.negword = "moins " + self.pointword = "virgule" + self.errmsg_nonnum = u"Seulement des nombres peuvent être convertis en mots." + self.errmsg_toobig = u"Nombre trop grand pour être converti en mots." + self.exclude_title = ["et", "virgule", "moins"] + self.mid_numwords = [(1000, "mille"), (100, "cent"), (90, "nonante"), + (80, "huitante"), (70, "septante"), (60, "soixante"), + (50, "cinquante"), (40, "quarante"), + (30, "trente")] + self.low_numwords = ["vingt", "dix-neuf", "dix-huit", "dix-sept", + "seize", "quinze", "quatorze", "treize", "douze", + "onze", "dix", "neuf", "huit", "sept", "six", + "cinq", "quatre", "trois", "deux", "un", "zéro"] + self.ords = { + "cinq": "cinquième", + "neuf": "neuvième", + } + + + def merge(self, curr, next): + ctext, cnum, ntext, nnum = curr + next + + if cnum == 1: + if nnum < 1000000: + return next + else: + # if (not (cnum - 80)%100 or not cnum%100) and ctext[-1] == "s": + # ctext = ctext[:-1] + if (cnum<1000 and nnum != 1000 and ntext[-1] != "s" + and not nnum%100): + ntext += "s" + + if nnum < cnum < 100: + if nnum % 10 == 1:# and cnum != 80: + return ("%s et %s"%(ctext, ntext), cnum + nnum) + return ("%s-%s"%(ctext, ntext), cnum + nnum) + elif nnum > cnum: + return ("%s %s"%(ctext, ntext), cnum * nnum) + return ("%s %s"%(ctext, ntext), cnum + nnum) + + + # Is this right for such things as 1001 - "mille unième" instead of + # "mille premier"?? "millième"?? + + def to_ordinal(self,value): + self.verify_ordinal(value) + if value == 1: + return "premier" + word = self.to_cardinal(value) + for src, repl in self.ords.items(): + if word.endswith(src): + word = word[:-len(src)] + repl + break + else: + if word[-1] == "e": + word = word[:-1] + word = word + "ième" + return word + + def to_ordinal_num(self, value): + self.verify_ordinal(value) + out = str(value) + out += {"1" : "er" }.get(out[-1], "me") + return out + + def to_currency(self, val, longval=True, old=False): + hightxt = "Euro/s" + if old: + hightxt="franc/s" + return self.to_splitnum(val, hightxt=hightxt, lowtxt="centime/s", + jointxt="et",longval=longval) + +n2w = Num2Word_FR_CH() +to_card = n2w.to_cardinal +to_ord = n2w.to_ordinal +to_ordnum = n2w.to_ordinal_num + +def main(): + for val in [ 1, 11, 12, 21, 31, 33, 71, 80, 81, 91, 99, 100, 101, 102, 155, + 180, 300, 308, 832, 1000, 1001, 1061, 1100, 1500, 1701, 3000, + 8280, 8291, 150000, 500000, 1000000, 2000000, 2000001, + -21212121211221211111, -2.121212, -1.0000100]: + n2w.test(val) + + n2w.test(1325325436067876801768700107601001012212132143210473207540327057320957032975032975093275093275093270957329057320975093272950730) + print n2w.to_currency(112121) + print n2w.to_year(1996) + + +if __name__ == "__main__": + main() diff --git a/tests/test_fr_ch.py b/tests/test_fr_ch.py new file mode 100644 index 0000000..97ba4e5 --- /dev/null +++ b/tests/test_fr_ch.py @@ -0,0 +1,36 @@ +# -*- encoding: utf-8 -*- +# Copyright (c) 2015, 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 unittest import TestCase + +from num2words import num2words + +class Num2WordsENTest(TestCase): + def test_ordinal_special_joins(self): + self.assertEqual(num2words(5, ordinal=True, lang='fr_CH'), "cinquième") + self.assertEqual(num2words(6, ordinal=True, lang='fr_CH'), "sixième") + self.assertEqual(num2words(35, ordinal=True, lang='fr_CH'), "trente-cinquième") + self.assertEqual(num2words(9, ordinal=True, lang='fr_CH'), "neuvième") + self.assertEqual(num2words(49, ordinal=True, lang='fr_CH'), "quarante-neuvième") + self.assertEqual(num2words(71, lang='fr_CH'), "septante et un") + self.assertEqual(num2words(81, lang='fr_CH'), "huitante et un") + self.assertEqual(num2words(80, lang='fr_CH'), "huitante") + self.assertEqual(num2words(880, lang='fr_CH'), "huit cents huitante") + self.assertEqual(num2words(91, ordinal=True, lang='fr_CH'), "nonante et unième") + self.assertEqual(num2words(53, lang='fr_CH'), "cinquante-trois") + From 51d34ce78eda8831b905fc29d0411bb173331090 Mon Sep 17 00:00:00 2001 From: mdc <201205975@post.au.dk> Date: Sat, 19 Mar 2016 22:21:14 +0100 Subject: [PATCH 11/99] Added functions that need to be overriden to lang_DK, created TODO's, added lang_DK to __init__ and added documentation to README --- README.rst | 1 + num2words/__init__.py | 2 + num2words/lang_DK.py | 172 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 175 insertions(+) create mode 100644 num2words/lang_DK.py diff --git a/README.rst b/README.rst index 96d41c3..d62183e 100644 --- a/README.rst +++ b/README.rst @@ -50,6 +50,7 @@ Besides the numerical argument, there's two optional arguments. * ``en_GB`` (British English) * ``en_IN`` (Indian English) * ``pl`` (Polish) +* ``dk`` (Danish) You can supply values like ``fr_FR``, the code will be correctly interpreted. If you supply an unsupported language, ``NotImplementedError`` is raised. diff --git a/num2words/__init__.py b/num2words/__init__.py index 220f0c3..acfa839 100644 --- a/num2words/__init__.py +++ b/num2words/__init__.py @@ -26,6 +26,7 @@ from . import lang_ES from . import lang_LT from . import lang_LV from . import lang_PL +from . import lang_DK CONVERTER_CLASSES = { 'en': lang_EN.Num2Word_EN(), @@ -38,6 +39,7 @@ CONVERTER_CLASSES = { 'lt': lang_LT.Num2Word_LT(), 'lv': lang_LV.Num2Word_LV(), 'pl': lang_PL.Num2Word_PL(), + 'dk': lang_DK.Num2Word_DK(), } def num2words(number, ordinal=False, lang='en'): diff --git a/num2words/lang_DK.py b/num2words/lang_DK.py new file mode 100644 index 0000000..7d30732 --- /dev/null +++ b/num2words/lang_DK.py @@ -0,0 +1,172 @@ +# Copyright (c) 2003, Taro Ogawa. All Rights Reserved. +# Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. + +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301 USA + +from __future__ import division, unicode_literals +from num2words import lang_EU + +class Num2Word_DK(lang_EU.Num2Word_EU): + def set_high_numwords(self, high): + max = 3 + 6*len(high) + for word, n in zip(high, range(max, 3, -6)): + self.cards[10**n] = word + "illard" + self.cards[10**(n-3)] = word + "illion" + + def setup(self): + self.negword = "minus " + self.pointword = "komma" + self.errmsg_nornum = "Kun tal kan blive konverteret til ord." + self.exclude_title = ["og", "komma", "minus"] + + self.mid_numwords = [(1000, "tusind"), (100, "hundrede"), + (90, "nitten"), (80, "firs"), (70, "halvfjerds"), + (60, "treds"), (50, "halvtreds"), (40, "fyrre"), + (30, "tredive")] + self.low_numwords = ["tyve", "nitten", "atten", "sytten", + "seksten", "femten", "fjorten", "tretten", + "tolv", "elleve", "ti", "ni", "\xe5tte", + "syv", "seks", "fem", "fire", "tre", "to", + "et", "nul"] + self.ords = { "en" : "f\xf8rste", + "to" : "anden", + "tre" : "tredje", + "fire" : "fjerde", + "fem" : "femte", + "seks" : "sjette", + "syv" : "syvende", + "otte" : "ottende", + "ni" : "niende", + "ti" : "tiende", + "elleve" : "ellevte", + "tolv" : "tolvte", + "tyve" : "tyvende" } + + + def merge(self, (ltext, lnum), (rtext, rnum)): + if lnum == 1 and rnum < 100: + return (rtext, rnum) + elif 100 > lnum > rnum : + return ("%s-%s"%(ltext, rtext), lnum + rnum) + elif lnum >= 100 > rnum: + return ("%s og %s"%(ltext, rtext), lnum + rnum) + elif rnum > lnum: + return ("%s %s"%(ltext, rtext), lnum * rnum) + return ("%s, %s"%(ltext, rtext), lnum + rnum) + + #TODO: skal returnere ordnum is 21ende, og ord is tyvende + def to_ordinal(self, value): + self.verify_ordinal(value) + outwords = self.to_cardinal(value).split(" ") + lastwords = outwords[-1].split("-") + lastword = lastwords[-1].lower() + try: + lastword = self.ords[lastword] + except KeyError: + if lastword[-2:] == "ti": + lastword = lastword + "ende" + else: + lastword += "de" + lastwords[-1] = self.title(lastword) + outwords[-1] = "".join(lastwords) + return " ".join(outwords) + + #TODO:Skal returnere "en" istedet for "et" i 21. + def to_splitnum(self, val, hightxt="", lowtxt="", jointxt="", + divisor=100, longval=True, cents = True): + out = [] + try: + high, low = val + except TypeError: + high, low = divmod(val, divisor) + if high: + hightxt = self.title(self.inflect(high, hightxt)) + out.append(self.to_cardinal(high)) + if low: + if longval: + if hightxt: + out.append(hightxt) + if jointxt: + out.append(self.title(jointxt)) + elif hightxt: + out.append(hightxt) + if low: + if cents: + out.append(self.to_cardinal(low)) + else: + out.append("%02d" % low) + if lowtxt and longval: + out.append(self.title(self.inflect(low, lowtxt))) + return " ".join(out) + + #TODO: 21 skal returnere enogtyve i card. + def to_cardinal(self, value): + try: + assert long(value) == value + except (ValueError, TypeError, AssertionError): + return self.to_cardinal_float(value) + + self.verify_num(value) + + out = "" + if value < 0: + value = abs(value) + out = self.negword + + if value >= self.MAXVAL: + raise OverflowError(self.errmsg_toobig % (value, self.MAXVAL)) + + + val = self.splitnum(value) + words, num = self.clean(val) + return self.title(out + words) + + + def to_ordinal_num(self, value): + self.verify_ordinal(value) + return "%s%s"%(value, self.to_ordinal(value)[-2:]) + + + def to_year(self, val, longval=True): + if not (val//100)%10: + return self.to_cardinal(val) + return self.to_splitnum(val, hightxt="hundrede", jointxt="og", + longval=longval) + + def to_currency(self, val, longval=True): + return self.to_splitnum(val, hightxt="krone/r", lowtxt="\xf8re/r", + jointxt="og", longval=longval, cents = True) + + +n2w = Num2Word_DK() +to_card = n2w.to_cardinal +to_ord = n2w.to_ordinal +to_ordnum = n2w.to_ordinal_num +to_year = n2w.to_year + +def main(): + n2w.test(21) + # for val in [ 1, 11, 12, 21, 31, 33, 71, 80, 81, 91, 99, 100, 101, 102, 155, + # 180, 300, 308, 832, 1000, 1001, 1061, 1100, 1500, 1701, 3000, + # 8280, 8291, 150000, 500000, 1000000, 2000000, 2000001, + # -21212121211221211111, -2.121212, -1.0000100]: + # n2w.test(val) + # n2w.test(1325325436067876801768700107601001012212132143210473207540327057320957032975032975093275093275093270957329057320975093272950730) + # for val in [1,120,1000,1120,1800, 1976,2000,2010,2099,2171]: + # print val, "er", n2w.to_currency(val) + # print val, "er", n2w.to_year(val) + + +if __name__ == "__main__": + main() From cce1455846ccb23e666e39d64d51a9292443b1d7 Mon Sep 17 00:00:00 2001 From: mdc <201205975@post.au.dk> Date: Mon, 21 Mar 2016 11:09:30 +0100 Subject: [PATCH 12/99] Added the German algorithms, and begun adjusting them. --- num2words/lang_DK.py | 143 +++++++++++++++---------------------------- 1 file changed, 49 insertions(+), 94 deletions(-) diff --git a/num2words/lang_DK.py b/num2words/lang_DK.py index 7d30732..551611d 100644 --- a/num2words/lang_DK.py +++ b/num2words/lang_DK.py @@ -21,8 +21,8 @@ class Num2Word_DK(lang_EU.Num2Word_EU): def set_high_numwords(self, high): max = 3 + 6*len(high) for word, n in zip(high, range(max, 3, -6)): - self.cards[10**n] = word + "illard" - self.cards[10**(n-3)] = word + "illion" + self.cards[10**n] = word + "illarder" + self.cards[10**(n-3)] = word + "illioner" def setup(self): self.negword = "minus " @@ -53,101 +53,57 @@ class Num2Word_DK(lang_EU.Num2Word_EU): "tolv" : "tolvte", "tyve" : "tyvende" } + def merge(self, curr, next): + ctext, cnum, ntext, nnum = curr + next + + if cnum == 1: + if nnum < 10**6 or self.ordflag: + return next + ctext = "en" + + if nnum > cnum: + if nnum >= 10**6: + ctext += " " + val = cnum * nnum + else: + if nnum < 10 < cnum < 100: + if nnum == 1: + ntext = "en" + ntext, ctext = ctext, ntext + "og" + elif cnum >= 10**6: + ctext += " " + val = cnum + nnum + + word = ctext + ntext + return (word, val) - def merge(self, (ltext, lnum), (rtext, rnum)): - if lnum == 1 and rnum < 100: - return (rtext, rnum) - elif 100 > lnum > rnum : - return ("%s-%s"%(ltext, rtext), lnum + rnum) - elif lnum >= 100 > rnum: - return ("%s og %s"%(ltext, rtext), lnum + rnum) - elif rnum > lnum: - return ("%s %s"%(ltext, rtext), lnum * rnum) - return ("%s, %s"%(ltext, rtext), lnum + rnum) - #TODO: skal returnere ordnum is 21ende, og ord is tyvende def to_ordinal(self, value): self.verify_ordinal(value) - outwords = self.to_cardinal(value).split(" ") - lastwords = outwords[-1].split("-") - lastword = lastwords[-1].lower() - try: - lastword = self.ords[lastword] - except KeyError: - if lastword[-2:] == "ti": - lastword = lastword + "ende" - else: - lastword += "de" - lastwords[-1] = self.title(lastword) - outwords[-1] = "".join(lastwords) - return " ".join(outwords) - - #TODO:Skal returnere "en" istedet for "et" i 21. - def to_splitnum(self, val, hightxt="", lowtxt="", jointxt="", - divisor=100, longval=True, cents = True): - out = [] - try: - high, low = val - except TypeError: - high, low = divmod(val, divisor) - if high: - hightxt = self.title(self.inflect(high, hightxt)) - out.append(self.to_cardinal(high)) - if low: - if longval: - if hightxt: - out.append(hightxt) - if jointxt: - out.append(self.title(jointxt)) - elif hightxt: - out.append(hightxt) - if low: - if cents: - out.append(self.to_cardinal(low)) - else: - out.append("%02d" % low) - if lowtxt and longval: - out.append(self.title(self.inflect(low, lowtxt))) - return " ".join(out) - - #TODO: 21 skal returnere enogtyve i card. - def to_cardinal(self, value): - try: - assert long(value) == value - except (ValueError, TypeError, AssertionError): - return self.to_cardinal_float(value) - - self.verify_num(value) - - out = "" - if value < 0: - value = abs(value) - out = self.negword - - if value >= self.MAXVAL: - raise OverflowError(self.errmsg_toobig % (value, self.MAXVAL)) - - - val = self.splitnum(value) - words, num = self.clean(val) - return self.title(out + words) + self.ordflag = True + outword = self.to_cardinal(value) + self.ordflag = False + for key in self.ords: + if outword.endswith(key): + outword = outword[:len(outword) - len(key)] + self.ords[key] + break + return outword + "te" + # Is this correct?? def to_ordinal_num(self, value): self.verify_ordinal(value) - return "%s%s"%(value, self.to_ordinal(value)[-2:]) + return str(value) + "te" + def to_currency(self, val, longval=True): + return self.to_splitnum(val, hightxt="kr", lowtxt="\xf8re", + jointxt="og",longval=longval) + def to_year(self, val, longval=True): if not (val//100)%10: return self.to_cardinal(val) - return self.to_splitnum(val, hightxt="hundrede", jointxt="og", - longval=longval) - - def to_currency(self, val, longval=True): - return self.to_splitnum(val, hightxt="krone/r", lowtxt="\xf8re/r", - jointxt="og", longval=longval, cents = True) - + return self.to_splitnum(val, hightxt="hundrede og", longval=longval) n2w = Num2Word_DK() to_card = n2w.to_cardinal @@ -156,16 +112,15 @@ to_ordnum = n2w.to_ordinal_num to_year = n2w.to_year def main(): - n2w.test(21) - # for val in [ 1, 11, 12, 21, 31, 33, 71, 80, 81, 91, 99, 100, 101, 102, 155, - # 180, 300, 308, 832, 1000, 1001, 1061, 1100, 1500, 1701, 3000, - # 8280, 8291, 150000, 500000, 1000000, 2000000, 2000001, - # -21212121211221211111, -2.121212, -1.0000100]: - # n2w.test(val) - # n2w.test(1325325436067876801768700107601001012212132143210473207540327057320957032975032975093275093275093270957329057320975093272950730) - # for val in [1,120,1000,1120,1800, 1976,2000,2010,2099,2171]: - # print val, "er", n2w.to_currency(val) - # print val, "er", n2w.to_year(val) + for val in [ 1, 11, 12, 21, 31, 33, 71, 80, 81, 91, 99, 100, 101, 102, 155, + 180, 300, 308, 832, 1000, 1001, 1061, 1100, 1500, 1701, 3000, + 8280, 8291, 150000, 500000, 1000000, 2000000, 2000001, + -21212121211221211111, -2.121212, -1.0000100]: + n2w.test(val) + n2w.test(1325325436067876801768700107601001012212132143210473207540327057320957032975032975093275093275093270957329057320975093272950730) + for val in [1,120,1000,1120,1800, 1976,2000,2010,2099,2171]: + print val, "er", n2w.to_currency(val) + print val, "er", n2w.to_year(val) if __name__ == "__main__": From 8fff34e3187460fecab4023c57521ffbae682bac Mon Sep 17 00:00:00 2001 From: mdc <201205975@post.au.dk> Date: Mon, 21 Mar 2016 14:16:06 +0100 Subject: [PATCH 13/99] Added og to hundreds, and a lot of other adjustments in the merge algorithm --- num2words/lang_DK.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/num2words/lang_DK.py b/num2words/lang_DK.py index 551611d..0534e93 100644 --- a/num2words/lang_DK.py +++ b/num2words/lang_DK.py @@ -31,12 +31,12 @@ class Num2Word_DK(lang_EU.Num2Word_EU): self.exclude_title = ["og", "komma", "minus"] self.mid_numwords = [(1000, "tusind"), (100, "hundrede"), - (90, "nitten"), (80, "firs"), (70, "halvfjerds"), + (90, "halvfems"), (80, "firs"), (70, "halvfjerds"), (60, "treds"), (50, "halvtreds"), (40, "fyrre"), (30, "tredive")] self.low_numwords = ["tyve", "nitten", "atten", "sytten", "seksten", "femten", "fjorten", "tretten", - "tolv", "elleve", "ti", "ni", "\xe5tte", + "tolv", "elleve", "ti", "ni", "otte", "syv", "seks", "fem", "fire", "tre", "to", "et", "nul"] self.ords = { "en" : "f\xf8rste", @@ -55,17 +55,22 @@ class Num2Word_DK(lang_EU.Num2Word_EU): def merge(self, curr, next): ctext, cnum, ntext, nnum = curr + next + if next[1] == 100 or next[1] == 1000: + lst = list(next) + lst[0] = 'et' + lst[0] + next = tuple(lst) if cnum == 1: if nnum < 10**6 or self.ordflag: return next ctext = "en" - if nnum > cnum: if nnum >= 10**6: ctext += " " val = cnum * nnum else: + if cnum >= 100 and cnum < 10000: + ctext += "og" if nnum < 10 < cnum < 100: if nnum == 1: ntext = "en" @@ -73,7 +78,6 @@ class Num2Word_DK(lang_EU.Num2Word_EU): elif cnum >= 10**6: ctext += " " val = cnum + nnum - word = ctext + ntext return (word, val) @@ -87,13 +91,11 @@ class Num2Word_DK(lang_EU.Num2Word_EU): if outword.endswith(key): outword = outword[:len(outword) - len(key)] + self.ords[key] break - return outword + "te" + return outword + "ende" - - # Is this correct?? def to_ordinal_num(self, value): self.verify_ordinal(value) - return str(value) + "te" + return str(value) + "ende" def to_currency(self, val, longval=True): @@ -103,7 +105,7 @@ class Num2Word_DK(lang_EU.Num2Word_EU): def to_year(self, val, longval=True): if not (val//100)%10: return self.to_cardinal(val) - return self.to_splitnum(val, hightxt="hundrede og", longval=longval) + return self.to_splitnum(val, hightxt="hundrede", longval=longval) n2w = Num2Word_DK() to_card = n2w.to_cardinal @@ -112,6 +114,7 @@ to_ordnum = n2w.to_ordinal_num to_year = n2w.to_year def main(): + #print to_card(308) 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, From b1bbe109fc5cfac5c6c0649a6153433292bb3e6c Mon Sep 17 00:00:00 2001 From: mdc <201205975@post.au.dk> Date: Mon, 21 Mar 2016 16:11:54 +0100 Subject: [PATCH 14/99] Corrected for special cases of currency and year --- num2words/lang_DK.py | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/num2words/lang_DK.py b/num2words/lang_DK.py index 0534e93..bc88c06 100644 --- a/num2words/lang_DK.py +++ b/num2words/lang_DK.py @@ -39,7 +39,8 @@ class Num2Word_DK(lang_EU.Num2Word_EU): "tolv", "elleve", "ti", "ni", "otte", "syv", "seks", "fem", "fire", "tre", "to", "et", "nul"] - self.ords = { "en" : "f\xf8rste", + self.ords = { "nul" : "nul", + "et" : "f\xf8rste", "to" : "anden", "tre" : "tredje", "fire" : "fjerde", @@ -51,7 +52,14 @@ class Num2Word_DK(lang_EU.Num2Word_EU): "ti" : "tiende", "elleve" : "ellevte", "tolv" : "tolvte", - "tyve" : "tyvende" } + "tretten" : "trett", + "fjorten" : "fjort", + "femten" : "femt", + "seksten" : "sekst", + "sytten" : "sytt", + "atten" : "att", + "nitten" : "nitt", + "tyve" : "tyv"} def merge(self, curr, next): ctext, cnum, ntext, nnum = curr + next @@ -69,8 +77,10 @@ class Num2Word_DK(lang_EU.Num2Word_EU): ctext += " " val = cnum * nnum else: - if cnum >= 100 and cnum < 10000: - ctext += "og" + if cnum >= 100 and cnum < 1000: + ctext += " og " + elif cnum >= 1000 and cnum <= 100000: + ctext += "e og " if nnum < 10 < cnum < 100: if nnum == 1: ntext = "en" @@ -91,18 +101,33 @@ class Num2Word_DK(lang_EU.Num2Word_EU): if outword.endswith(key): outword = outword[:len(outword) - len(key)] + self.ords[key] break - return outword + "ende" + if value %100 >= 30 and value %100 <= 39 or value %100 == 0: + outword += "te" + elif value % 100 > 12 or value %100 == 0: + outword += "ende" + return outword def to_ordinal_num(self, value): self.verify_ordinal(value) + vaerdte = (0,1,5,6,11,12) + if value %100 >= 30 and value %100 <= 39 or value % 100 in vaerdte: + return str(value) + "te" + elif value % 100 == 2: + return str(value) + "en" return str(value) + "ende" def to_currency(self, val, longval=True): + if val//100 == 1 or val == 1: + ret = self.to_splitnum(val, hightxt="kr", lowtxt="\xf8re", + jointxt="og",longval=longval) + return "en " + ret[3:] return self.to_splitnum(val, hightxt="kr", lowtxt="\xf8re", jointxt="og",longval=longval) def to_year(self, val, longval=True): + if val == 1: + return 'en' if not (val//100)%10: return self.to_cardinal(val) return self.to_splitnum(val, hightxt="hundrede", longval=longval) @@ -114,17 +139,16 @@ to_ordnum = n2w.to_ordinal_num to_year = n2w.to_year def main(): - #print to_card(308) for val in [ 1, 11, 12, 21, 31, 33, 71, 80, 81, 91, 99, 100, 101, 102, 155, 180, 300, 308, 832, 1000, 1001, 1061, 1100, 1500, 1701, 3000, 8280, 8291, 150000, 500000, 1000000, 2000000, 2000001, -21212121211221211111, -2.121212, -1.0000100]: n2w.test(val) n2w.test(1325325436067876801768700107601001012212132143210473207540327057320957032975032975093275093275093270957329057320975093272950730) - for val in [1,120,1000,1120,1800, 1976,2000,2010,2099,2171]: + for val in [1,120, 160, 1000,1120,1800, 1976,2000,2010,2099,2171]: print val, "er", n2w.to_currency(val) print val, "er", n2w.to_year(val) - + n2w.test(65132) if __name__ == "__main__": main() From b9b6a8de428a7252a978fb3fd6735a4ec6312d02 Mon Sep 17 00:00:00 2001 From: alexpantyukhin Date: Tue, 15 Dec 2015 04:24:57 +0000 Subject: [PATCH 15/99] add ru lang into supported languages --- README.rst | 1 + num2words/__init__.py | 2 + num2words/lang_RU.py | 309 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 312 insertions(+) create mode 100644 num2words/lang_RU.py diff --git a/README.rst b/README.rst index 96d41c3..9902146 100644 --- a/README.rst +++ b/README.rst @@ -50,6 +50,7 @@ Besides the numerical argument, there's two optional arguments. * ``en_GB`` (British English) * ``en_IN`` (Indian English) * ``pl`` (Polish) +* ``ru`` (Russian) You can supply values like ``fr_FR``, the code will be correctly interpreted. If you supply an unsupported language, ``NotImplementedError`` is raised. diff --git a/num2words/__init__.py b/num2words/__init__.py index 220f0c3..24830b7 100644 --- a/num2words/__init__.py +++ b/num2words/__init__.py @@ -26,6 +26,7 @@ from . import lang_ES from . import lang_LT from . import lang_LV from . import lang_PL +from . import lang_RU CONVERTER_CLASSES = { 'en': lang_EN.Num2Word_EN(), @@ -38,6 +39,7 @@ CONVERTER_CLASSES = { 'lt': lang_LT.Num2Word_LT(), 'lv': lang_LV.Num2Word_LV(), 'pl': lang_PL.Num2Word_PL(), + 'ru': lang_RU.Num2Word_RU(), } def num2words(number, ordinal=False, lang='en'): diff --git a/num2words/lang_RU.py b/num2words/lang_RU.py new file mode 100644 index 0000000..328b336 --- /dev/null +++ b/num2words/lang_RU.py @@ -0,0 +1,309 @@ +# -*- encoding: utf-8 -*- +# Copyright (c) 2003, Taro Ogawa. All Rights Reserved. +# Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. + +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301 USA +u""" +>>> from textwrap import fill + +>>> ' '.join([str(i) for i in splitby3('1')]) +u'1' +>>> ' '.join([str(i) for i in splitby3('1123')]) +u'1 123' +>>> ' '.join([str(i) for i in splitby3('1234567890')]) +u'1 234 567 890' + +>>> print(' '.join([n2w(i) for i in range(10)])) +ноль один два три четыре пять шесть семь восемь девять + +>>> print(fill(' '.join([n2w(i+10) for i in range(10)]))) +десять одиннадцать двенадцать тринадцать четырнадцать пятнадцать +шестнадцать семнадцать восемнадцать девятнадцать + +>>> print(fill(' '.join([n2w(i*10) for i in range(10)]))) +ноль десять двадцать тридцать сорок пятьдесят шестьдесят семьдесят +восемьдесят девяносто + +>>> print(n2w(100)) +сто +>>> print(n2w(101)) +сто один +>>> print(n2w(110)) +сто десять +>>> print(n2w(115)) +сто пятнадцать +>>> print(n2w(123)) +сто двадцать три +>>> print(n2w(1000)) +тысяча +>>> print(n2w(1001)) +тысяча один +>>> print(n2w(2012)) +две тысячи двенадцать + +>>> print(n2w(12519.85)) +двенадцать тысяч пятьсот девятнадцать запятая восемьдесят пять + +>>> print(fill(n2w(1234567890))) +миллиард двести тридцать четыре миллиона пятьсот шестьдесят семь тысяч +восемьсот девяносто + +>>> print(fill(n2w(215461407892039002157189883901676))) +двести пятнадцать нониллионов четыреста шестьдесят один октиллион +четыреста семь септиллионов восемьсот девяносто два секстиллиона +тридцать девять квинтиллионов два квадриллиона сто пятьдесят семь +триллионов сто восемьдесят девять миллиардов восемьсот восемьдесят три +миллиона девятьсот одна тысяча шестьсот семьдесят шесть + +>>> print(fill(n2w(719094234693663034822824384220291))) +семьсот девятнадцать нониллионов девяносто четыре октиллиона двести +тридцать четыре септиллиона шестьсот девяносто три секстиллиона +шестьсот шестьдесят три квинтиллиона тридцать четыре квадриллиона +восемьсот двадцать два триллиона восемьсот двадцать четыре миллиарда +триста восемьдесят четыре миллиона двести двадцать тысяч двести +девяносто один + +>>> print(to_currency(1.0, 'EUR')) +один евро, ноль центов + +>>> print(to_currency(1.0, 'RUB')) +один рубль, ноль копеек + +>>> print(to_currency(1234.56, 'EUR')) +тысяча двести тридцать четыре евро, пятьдесят шесть центов + +>>> print(to_currency(1234.56, 'RUB')) +тысяча двести тридцать четыре рубля, пятьдесят шесть копеек + +>>> print(to_currency(10111, 'EUR', seperator=u' и')) +сто один евро и одиннадцать центов + +>>> print(to_currency(10121, 'RUB', seperator=u' и')) +сто один рубль и двадцать одна копейка + +>>> print(to_currency(10122, 'RUB', seperator=u' и')) +сто один рубль и двадцать две копейки + +>>> print(to_currency(10121, 'EUR', seperator=u' и')) +сто один евро и двадцать один цент + +>>> print(to_currency(-1251985, cents = False)) +минус двенадцать тысяч пятьсот девятнадцать евро, 85 центов +""" +from __future__ import unicode_literals + +ZERO = (u'ноль',) + +ONES_FEMININE = { + 1: (u'одна',), + 2: (u'две',), + 3: (u'три',), + 4: (u'четыре',), + 5: (u'пять',), + 6: (u'шесть',), + 7: (u'семь',), + 8: (u'восемь',), + 9: (u'девять',), +} + +ONES = { + 1: (u'один',), + 2: (u'два',), + 3: (u'три',), + 4: (u'четыре',), + 5: (u'пять',), + 6: (u'шесть',), + 7: (u'семь',), + 8: (u'восемь',), + 9: (u'девять',), +} + +TENS = { + 0: (u'десять',), + 1: (u'одиннадцать',), + 2: (u'двенадцать',), + 3: (u'тринадцать',), + 4: (u'четырнадцать',), + 5: (u'пятнадцать',), + 6: (u'шестнадцать',), + 7: (u'семнадцать',), + 8: (u'восемнадцать',), + 9: (u'девятнадцать',), +} + +TWENTIES = { + 2: (u'двадцать',), + 3: (u'тридцать',), + 4: (u'сорок',), + 5: (u'пятьдесят',), + 6: (u'шестьдесят',), + 7: (u'семьдесят',), + 8: (u'восемьдесят',), + 9: (u'девяносто',), +} + +HUNDREDS = { + 1: (u'сто',), + 2: (u'двести',), + 3: (u'триста',), + 4: (u'четыреста',), + 5: (u'пятьсот',), + 6: (u'шестьсот',), + 7: (u'семьсот',), + 8: (u'восемьсот',), + 9: (u'девятьсот',), +} + +THOUSANDS = { + 1: (u'тысяча', u'тысячи', u'тысяч'), # 10^3 + 2: (u'миллион', u'миллиона', u'миллионов'), # 10^6 + 3: (u'миллиард', u'миллиарда', u'миллиардов'), # 10^9 + 4: (u'триллион', u'триллиона', u'триллионов'), # 10^12 + 5: (u'квадриллион', u'квадриллиона', u'квадриллионов'), # 10^15 + 6: (u'квинтиллион', u'квинтиллиона', u'квинтиллионов'), # 10^18 + 7: (u'секстиллион', u'секстиллиона', u'секстиллионов'), # 10^21 + 8: (u'септиллион', u'септиллиона', u'септиллионов'), # 10^24 + 9: (u'октиллион', u'октиллиона', u'октиллионов'), #10^27 + 10: (u'нониллион', u'нониллиона', u'нониллионов'), # 10^30 +} + +CURRENCIES = { + 'RUB': ( + (u'рубль', u'рубля', u'рублей'), (u'копейка', u'копейки', u'копеек') + ), + 'EUR': ( + (u'евро', u'евро', u'евро'), (u'цент', u'цента', u'центов') + ), +} + + +def splitby3(n): + length = len(n) + if length > 3: + start = length % 3 + if start > 0: + yield int(n[:start]) + for i in range(start, length, 3): + yield int(n[i:i+3]) + else: + yield int(n) + + +def get_digits(n): + return [int(x) for x in reversed(list(('%03d' % n)[-3:]))] + + +def pluralize(n, forms): + if (n % 100 < 10 or n % 100 > 20): + if n % 10 == 1: + form = 0 + elif (n % 10 > 1 and n % 10 < 5): + form = 1 + else: + form = 2 + else: + form = 2 + return forms[form] + + +def int2word(n, feminine=False): + if n == 0: + return ZERO[0] + + words = [] + chunks = list(splitby3(str(n))) + i = len(chunks) + for x in chunks: + i -= 1 + n1, n2, n3 = get_digits(x) + + if n3 > 0: + words.append(HUNDREDS[n3][0]) + + if n2 > 1: + words.append(TWENTIES[n2][0]) + + if n2 == 1: + words.append(TENS[n1][0]) + elif n1 > 0 and not (i > 0 and x == 1): + ones = ONES_FEMININE if i == 1 or feminine and i == 0 else ONES + words.append(ones[n1][0]) + + if i > 0: + words.append(pluralize(x, THOUSANDS[i])) + + return ' '.join(words) + + +def n2w(n): + n = str(n).replace(',', '.') + if '.' in n: + left, right = n.split('.') + return u'%s запятая %s' % (int2word(int(left)), int2word(int(right))) + else: + return int2word(int(n)) + + +def to_currency(n, currency='EUR', cents=True, seperator=','): + if type(n) == int: + if n < 0: + minus = True + else: + minus = False + + n = abs(n) + left = n / 100 + right = n % 100 + else: + n = str(n).replace(',', '.') + if '.' in n: + left, right = n.split('.') + else: + left, right = n, 0 + left, right = int(left), int(right) + minus = False + cr1, cr2 = CURRENCIES[currency] + + if minus: + minus_str = "минус " + else: + minus_str = "" + + if cents: + cents_feminine = currency == 'RUB' + cents_str = int2word(right, cents_feminine) + else: + cents_str = "%02d" % right + + return u'%s%s %s%s %s %s' % ( + minus_str, + int2word(left), + pluralize(left, cr1), + seperator, + cents_str, + pluralize(right, cr2) + ) + + +class Num2Word_RU(object): + def to_cardinal(self, number): + return n2w(number) + + def to_ordinal(self, number): + raise NotImplementedError() + + +if __name__ == '__main__': + import doctest + doctest.testmod() From d3d0af304065f63b21db062ad2ac862ff30771be Mon Sep 17 00:00:00 2001 From: isnani Date: Fri, 18 Dec 2015 03:17:17 +0100 Subject: [PATCH 16/99] add indonesian ('id') --- num2words/__init__.py | 2 + num2words/base.py | 2 +- num2words/lang_ID.py | 194 ++++++++++++++++++++++++++++++++++++++++++ tests/test_id.py | 49 +++++++++++ 4 files changed, 246 insertions(+), 1 deletion(-) create mode 100644 num2words/lang_ID.py create mode 100644 tests/test_id.py diff --git a/num2words/__init__.py b/num2words/__init__.py index 24830b7..d0c8eb1 100644 --- a/num2words/__init__.py +++ b/num2words/__init__.py @@ -27,6 +27,7 @@ from . import lang_LT from . import lang_LV from . import lang_PL from . import lang_RU +from . import lang_ID CONVERTER_CLASSES = { 'en': lang_EN.Num2Word_EN(), @@ -36,6 +37,7 @@ CONVERTER_CLASSES = { 'fr_CH': lang_FR_CH.Num2Word_FR_CH(), 'de': lang_DE.Num2Word_DE(), 'es': lang_ES.Num2Word_ES(), + 'id': lang_ID.Num2Word_ID(), 'lt': lang_LT.Num2Word_LT(), 'lv': lang_LV.Num2Word_LV(), 'pl': lang_PL.Num2Word_PL(), diff --git a/num2words/base.py b/num2words/base.py index b2b7cab..bc0c5b9 100644 --- a/num2words/base.py +++ b/num2words/base.py @@ -182,7 +182,7 @@ class Num2Word_Base(object): pass - def to_ordinal(value): + def to_ordinal(self, value): return self.to_cardinal(value) diff --git a/num2words/lang_ID.py b/num2words/lang_ID.py new file mode 100644 index 0000000..ee07065 --- /dev/null +++ b/num2words/lang_ID.py @@ -0,0 +1,194 @@ +# 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 + +class Num2Word_ID(): + + BASE = {0: [], + 1: ["satu"], + 2: ["dua"], + 3: ["tiga"], + 4: ["empat"], + 5: ["lima"], + 6: ["enam"], + 7: ["tujuh"], + 8: ["delapan"], + 9: ["sembilan"]} + + TENS_TO = {3: "ribu", + 6: "juta", + 9: "miliar", + 12: "triliun", + 15: "kuadriliun", + 18: "kuantiliun", + 21: "sekstiliun", + 24: "septiliun", + 27: "oktiliun", + 30: "noniliun", + 33: "desiliun"} + + errmsg_floatord = "Cannot treat float number as ordinal" + errmsg_negord = "Cannot treat negative number as ordinal" + errmsg_toobig = "Too large" + max_num = 10**36 + + def split_by_koma(self, number): + return str(number).split('.') + + def split_by_3(self, number): + """ + starting here, it groups the number by three from the tail + '1234567' -> (('1',),('234',),('567',)) + :param number:str + :rtype:tuple + """ + blocks = () + length = len(number) + + if length < 3: + blocks += ((number,),) + else: + len_of_first_block = length % 3 + + if len_of_first_block > 0: + first_block = number[0:len_of_first_block], + blocks += first_block, + + for i in range(len_of_first_block, length, 3): + next_block = (number[i:i+3],), + blocks += next_block + + return blocks + + def spell(self, blocks): + """ + it adds the list of spelling to the blocks + (('1',),('034',)) -> (('1',['satu']),('234',['tiga', 'puluh', 'empat'])) + :param blocks: tuple + :rtype: tuple + """ + word_blocks = () + first_block = blocks[0] + if len(first_block[0]) == 1: + if first_block[0] == '0': + spelling = ['nol'] + else: + spelling = self.BASE[int(first_block[0])] + elif len(first_block[0]) == 2: + spelling = self.puluh(first_block[0]) + else: + spelling = self.ratus(first_block[0][0]) + self.puluh(first_block[0][1:3]) + + word_blocks += (first_block[0], spelling), + + for block in blocks[1:]: + spelling = self.ratus(block[0][0]) + self.puluh(block[0][1:3]) + block += spelling, + word_blocks += block, + + return word_blocks + + def ratus(self, number): + # it is used to spell + if number == '1': + return ['seratus'] + elif number == '0': + return [] + else: + return self.BASE[int(number)]+['ratus'] + + def puluh(self, number): + # it is used to spell + if number[0] == '1': + if number[1]== '0': + return ['sepuluh'] + elif number[1] == '1': + return ['sebelas'] + else: + return self.BASE[int(number[1])]+['belas'] + elif number[0] == '0': + return self.BASE[int(number[1])] + else: + return self.BASE[int(number[0])]+['puluh']+ self.BASE[int(number[1])] + + def spell_float(self, float_part): + # spell the float number + word_list = [] + for n in float_part: + if n == '0': + word_list += ['nol'] + continue + word_list += self.BASE[int(n)] + return ' '.join(['','koma']+word_list) + + def join(self, word_blocks, float_part): + """ + join the words by first join lists in the tuple + :param word_blocks: tuple + :rtype: str + """ + word_list = [] + length = len(word_blocks)-1 + first_block = word_blocks[0], + start = 0 + + if length == 1 and first_block[0][0] == '1': + word_list += ['seribu'] + start = 1 + + for i in range(start, length+1, 1): + word_list += word_blocks[i][1] + if not word_blocks[i][1]: + continue + if i == length: + break + word_list += [self.TENS_TO[(length-i)*3]] + + return ' '.join(word_list)+float_part + + def to_cardinal(self, number): + if number >= self.max_num: + raise OverflowError(self.errmsg_toobig % (number, self.maxnum)) + minus = '' + if number < 0: + minus = 'min ' + float_word = '' + n = self.split_by_koma(abs(number)) + if len(n)==2: + float_word = self.spell_float(n[1]) + return minus + self.join(self.spell(self.split_by_3(n[0])), float_word) + + def to_ordinal(self, number): + self.verify_ordinal(number) + out_word = self.to_cardinal(number) + if out_word == "satu": + return "pertama" + return "ke" + out_word + + def to_ordinal_num(self, number): + self.verify_ordinal(number) + return "ke-" + str(number) + + def to_currency(self, value): + return self.to_cardinal(value)+" rupiah" + + def to_year(self, value): + return self.to_cardinal(value) + + def verify_ordinal(self, value): + if not value == long(value): + raise TypeError, self.errmsg_floatord %(value) + if not abs(value) == value: + raise TypeError, self.errmsg_negord %(value) diff --git a/tests/test_id.py b/tests/test_id.py new file mode 100644 index 0000000..a1716a0 --- /dev/null +++ b/tests/test_id.py @@ -0,0 +1,49 @@ +# 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 unittest import TestCase + +from num2words import num2words + +class Num2WordsIDTest(TestCase): + def test_cardinal_for_natural_number(self): + self.assertEqual(num2words(10, lang='id'), "sepuluh") + self.assertEqual(num2words(11, lang='id'), "sebelas") + self.assertEqual(num2words(108, lang='id'), "seratus delapan") + self.assertEqual(num2words(1075, lang='id'), "seribu tujuh puluh lima") + self.assertEqual(num2words(1087231, lang='id'), "satu juta delapan puluh tujuh ribu dua ratus tiga puluh satu") + self.assertEqual(num2words(1000000408, lang='id'), "satu miliar empat ratus delapan") + + def test_cardinal_for_decimal_number(self): + self.assertEqual(num2words(12.234, lang='id'), "dua belas koma dua tiga empat") + self.assertEqual(num2words(9.076, lang='id'), "sembilan koma nol tujuh enam") + + def test_cardinal_for_negative_number(self): + self.assertEqual(num2words(-923, lang='id'), "min sembilan ratus dua puluh tiga") + self.assertEqual(num2words(-0.234, lang='id'), "min nol koma dua tiga empat") + + def test_ordinal_for_natural_number(self): + self.assertEqual(num2words(1, ordinal=True, lang='id'), "pertama") + self.assertEqual(num2words(10, ordinal=True, lang='id'), "kesepuluh") + + #def test_ordinal_numeric_for_natural_number(self): + # self.assertEqual(num2words(1, ordinal=True, lang='id'), "ke-1") + # self.assertEqual(num2words(10, ordinal=True, lang='id'), "ke-10") + + def test_ordinal_for_negative_number(self): + self.assertRaises(TypeError, num2words, -12, ordinal=True, lang='id') + + def test_ordinal_for_floating_number(self): + self.assertRaises(TypeError, num2words, 3.243, ordinal=True, lang='id') From 266fb9d2dfa2ea3e94c86c4cf7dd3f88d7bb9fcb Mon Sep 17 00:00:00 2001 From: Ernesto Rodriguez Ortiz Date: Thu, 31 Mar 2016 14:15:25 -0400 Subject: [PATCH 17/99] Fix regression added in the PR Iss24. --- num2words/base.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/num2words/base.py b/num2words/base.py index bc0c5b9..6e910e7 100644 --- a/num2words/base.py +++ b/num2words/base.py @@ -116,6 +116,7 @@ class Num2Word_Base(object): pre = int(value) post = str(abs(value - pre) * 10**self.precision) + post = '0' * (self.precision - len(post.split('.')[0])) + post out = [self.to_cardinal(pre)] if self.precision: @@ -123,7 +124,7 @@ class Num2Word_Base(object): for i in range(self.precision): curr = int(post[i]) - out.append(str(self.to_cardinal(curr))) + out.append(unicode(self.to_cardinal(curr))) return " ".join(out) From 3cafa38ddb9d7472117923025e7f2f5f1f533702 Mon Sep 17 00:00:00 2001 From: AntonKorobkov Date: Thu, 4 Aug 2016 18:47:13 +0300 Subject: [PATCH 18/99] added Russian language test with some basic coverage --- tests/test_ru.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 tests/test_ru.py diff --git a/tests/test_ru.py b/tests/test_ru.py new file mode 100644 index 0000000..fc6edce --- /dev/null +++ b/tests/test_ru.py @@ -0,0 +1,27 @@ +# -*- encoding: utf-8 -*- +# 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 unittest import TestCase + +from num2words import num2words + +class Num2WordsRUTest(TestCase): + + def test_cardinal(self): + self.assertEqual(num2words(5, lang='ru'), u"пять") + self.assertEqual(num2words(15, lang='ru'), u"пятнадцать") + self.assertEqual(num2words(154, lang='ru'), u"сто пятьдесят четыре") + self.assertEqual(num2words(418531, lang='ru'), u"четыреста восемнадцать тысяч пятьсот тридцать один") \ No newline at end of file From a63cee01dac047bd3718c4f064f4362dfce065f0 Mon Sep 17 00:00:00 2001 From: AntonKorobkov Date: Sun, 7 Aug 2016 20:28:14 +0300 Subject: [PATCH 19/99] floating point numbers test added --- tests/test_ru.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/test_ru.py b/tests/test_ru.py index fc6edce..9ba224b 100644 --- a/tests/test_ru.py +++ b/tests/test_ru.py @@ -24,4 +24,8 @@ class Num2WordsRUTest(TestCase): self.assertEqual(num2words(5, lang='ru'), u"пять") self.assertEqual(num2words(15, lang='ru'), u"пятнадцать") self.assertEqual(num2words(154, lang='ru'), u"сто пятьдесят четыре") - self.assertEqual(num2words(418531, lang='ru'), u"четыреста восемнадцать тысяч пятьсот тридцать один") \ No newline at end of file + self.assertEqual(num2words(418531, lang='ru'), u"четыреста восемнадцать тысяч пятьсот тридцать один") + + def test_floating_point(self): + self.assertEqual(num2words(5.2, lang='ru'), u"пять запятая два") + self.assertEqual(num2words(561.42, lang='ru'), u"пятьсот шестьдесят один запятая сорок два") From 4e5c07522c3d9afc52b07389c933c5ff17c1d255 Mon Sep 17 00:00:00 2001 From: Magno Costa - Akretion Date: Tue, 9 Aug 2016 18:30:46 -0300 Subject: [PATCH 20/99] In Brazilian Portuguese the decimal sign is comma ',' instead of dot '.'. Ex.: we use 1,01 instead of 1.01 --- num2words/lang_PT_BR.py | 4 ++-- tests/test_pt_BR.py | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/num2words/lang_PT_BR.py b/num2words/lang_PT_BR.py index bf4a8f3..88a8416 100644 --- a/num2words/lang_PT_BR.py +++ b/num2words/lang_PT_BR.py @@ -30,9 +30,9 @@ class Num2Word_PT_BR(lang_EU.Num2Word_EU): def setup(self): self.negword = "menos " - self.pointword = "ponto" + self.pointword = "vírgula" self.errmsg_nornum = "Somente números podem ser convertidos para palavras" - self.exclude_title = ["e", "ponto", "menos"] + self.exclude_title = ["e", "vírgula", "menos"] self.mid_numwords = [ (1000, "mil"), (100, "cem"), (90, "noventa"), diff --git a/tests/test_pt_BR.py b/tests/test_pt_BR.py index d2f4b22..9a82481 100644 --- a/tests/test_pt_BR.py +++ b/tests/test_pt_BR.py @@ -81,18 +81,18 @@ class Num2WordsPTBRTest(TestCase): def test_cardinal_float(self): self.assertEquals(num2words(Decimal('1.00'), lang='pt_BR'), 'um') - self.assertEquals(num2words(Decimal('1.01'), lang='pt_BR'), 'um ponto zero um') - self.assertEquals(num2words(Decimal('1.035'), lang='pt_BR'), 'um ponto zero três') - self.assertEquals(num2words(Decimal('1.35'), lang='pt_BR'), 'um ponto três cinco') - self.assertEquals(num2words(Decimal('3.14159'), lang='pt_BR'), 'três ponto um quatro') - self.assertEquals(num2words(Decimal('101.22'), lang='pt_BR'), 'cento e um ponto dois dois') - self.assertEquals(num2words(Decimal('2345.75'), lang='pt_BR'), 'dois mil, trezentos e quarenta e cinco ponto sete cinco') + self.assertEquals(num2words(Decimal('1.01'), lang='pt_BR'), 'um vírgula zero um') + self.assertEquals(num2words(Decimal('1.035'), lang='pt_BR'), 'um vírgula zero três') + self.assertEquals(num2words(Decimal('1.35'), lang='pt_BR'), 'um vírgula três cinco') + self.assertEquals(num2words(Decimal('3.14159'), lang='pt_BR'), 'três vírgula um quatro') + self.assertEquals(num2words(Decimal('101.22'), lang='pt_BR'), 'cento e um vírgula dois dois') + self.assertEquals(num2words(Decimal('2345.75'), lang='pt_BR'), 'dois mil, trezentos e quarenta e cinco vírgula sete cinco') def test_cardinal_float_negative(self): - self.assertEquals(num2words(Decimal('-2.34'), lang='pt_BR'), 'menos dois ponto três quatro') - self.assertEquals(num2words(Decimal('-9.99'), lang='pt_BR'), 'menos nove ponto nove nove') - self.assertEquals(num2words(Decimal('-7.01'), lang='pt_BR'), 'menos sete ponto zero um') - self.assertEquals(num2words(Decimal('-222.22'), lang='pt_BR'), 'menos duzentos e vinte e dois ponto dois dois') + self.assertEquals(num2words(Decimal('-2.34'), lang='pt_BR'), 'menos dois vírgula três quatro') + self.assertEquals(num2words(Decimal('-9.99'), lang='pt_BR'), 'menos nove vírgula nove nove') + self.assertEquals(num2words(Decimal('-7.01'), lang='pt_BR'), 'menos sete vírgula zero um') + self.assertEquals(num2words(Decimal('-222.22'), lang='pt_BR'), 'menos duzentos e vinte e dois vírgula dois dois') def test_ordinal(self): self.assertEquals(num2words(1, lang='pt_BR', ordinal=True), 'primeiro') From f98341731ed6804aa8a0e52e5363ba99846cab91 Mon Sep 17 00:00:00 2001 From: AntonKorobkov Date: Wed, 10 Aug 2016 18:06:46 +0300 Subject: [PATCH 21/99] added support for negative integers for Russian language --- num2words/lang_RU.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/num2words/lang_RU.py b/num2words/lang_RU.py index 328b336..922a852 100644 --- a/num2words/lang_RU.py +++ b/num2words/lang_RU.py @@ -218,6 +218,9 @@ def pluralize(n, forms): def int2word(n, feminine=False): + if n < 0: + return ' '.join([u'минус', int2word(abs(n))]) + if n == 0: return ZERO[0] From 273349a2347f487d5d8fb4de329ef101a2cf379c Mon Sep 17 00:00:00 2001 From: mr Date: Mon, 15 Aug 2016 13:09:18 +0200 Subject: [PATCH 22/99] Translation of error messages See https://github.com/savoirfairelinux/num2words/pull/45 --- num2words/lang_DE.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/num2words/lang_DE.py b/num2words/lang_DE.py index c9f73eb..252ccb7 100644 --- a/num2words/lang_DE.py +++ b/num2words/lang_DE.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # Copyright (c) 2003, Taro Ogawa. All Rights Reserved. # Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. @@ -17,7 +18,6 @@ from __future__ import unicode_literals from .lang_EU import Num2Word_EU -#//TODO: Use German error messages class Num2Word_DE(Num2Word_EU): def set_high_numwords(self, high): max = 3 + 6*len(high) @@ -29,8 +29,10 @@ class Num2Word_DE(Num2Word_EU): def setup(self): self.negword = "minus " self.pointword = "Komma" - self.errmsg_nonnum = "Only numbers may be converted to words." - self.errmsg_toobig = "Number is too large to convert to words." + self.errmsg_floatord = "Die Gleitkommazahl %s kann nicht in eine Ordnungszahl konvertiert werden." # "Cannot treat float %s as ordinal." + self.errmsg_nonnum = "Nur Zahlen (type(%s)) können in Wörter konvertiert werden." # "type(((type(%s)) ) not in [long, int, float]" + self.errmsg_negord = "Die negative Zahl %s kann nicht in eine Ordnungszahl konvertiert werden." # "Cannot treat negative num %s as ordinal." + self.errmsg_toobig = "Die Zahl %s muss kleiner als %s sein." # "abs(%s) must be less than %s." self.exclude_title = [] lows = ["non", "okt", "sept", "sext", "quint", "quadr", "tr", "b", "m"] From 22072268736c9652c2f478454fcf1def80beaa4d Mon Sep 17 00:00:00 2001 From: Alexey Porotnikov Date: Tue, 13 Sep 2016 10:05:43 +0300 Subject: [PATCH 23/99] add actual Lithuanian currency (euro since 1 January 2015) --- num2words/lang_LT.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/num2words/lang_LT.py b/num2words/lang_LT.py index d70c39b..a274e4a 100644 --- a/num2words/lang_LT.py +++ b/num2words/lang_LT.py @@ -85,7 +85,13 @@ vienas litas, nulis centų vienas tūkstantis du šimtai trisdešimt keturi litai, penkiasdešimt šeši centai >>> print(to_currency(-1251985, cents = False)) -minus dvylika tūkstančių penki šimtai devyniolika litų, 85 centai +minus dvylika tūkstančių penki šimtai devyniolika eurų, 85 centai + +>>> print(to_currency(1.0, 'EUR')) +vienas euras, nulis centų + +>>> print(to_currency(1234.56, 'EUR')) +vienas tūkstantis du šimtai trisdešimt keturi eurai, penkiasdešimt šeši centai """ from __future__ import unicode_literals @@ -144,6 +150,7 @@ THOUSANDS = { CURRENCIES = { 'LTL': ((u'litas', u'litai', u'litų'), (u'centas', u'centai', u'centų')), + 'EUR': ((u'euras', u'eurai', u'eurų'), (u'centas', u'centai', u'centų')), } def splitby3(n): @@ -210,7 +217,7 @@ def n2w(n): else: return int2word(int(n)) -def to_currency(n, currency='LTL', cents = True): +def to_currency(n, currency='EUR', cents = True): if type(n) == int: if n < 0: minus = True From 0e06eb81dde3ccb4a5f35d6eaf08a4c10d1130a8 Mon Sep 17 00:00:00 2001 From: Virgil Dupras Date: Tue, 18 Oct 2016 09:46:11 -0400 Subject: [PATCH 24/99] v0.5.4 --- CHANGES.rst | 15 +++++++++++++++ setup.py | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index f7f9d28..d9dd429 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,6 +1,21 @@ Changelog ========= +Version 0.5.4 -- 2016/10/18 +--------------------------- + +* Tons of new languages! +* Add Polish localization. (#23) +* Add Swiss-French localization. (#38) +* Add Russian localization. (#28, #46, #48) +* Add Indonesian localization. (#29) +* Add Norwegian localization. (#33) +* Add Danish localization. (#40) +* Add Brazilian localization. (#37, #47) +* Improve German localization. (#25, #27, #49) +* Improve Lithuanian localization. (#52) +* Improve floating point spelling. (#24) + Version 0.5.3 -- 2015/06/09 --------------------------- diff --git a/setup.py b/setup.py index 693ea27..b842523 100644 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ LONG_DESC = open('README.rst', 'rt').read() + '\n\n' + open('CHANGES.rst', 'rt') setup( name='num2words', - version='0.5.3', + version='0.5.4', description='Modules to convert numbers to words. Easily extensible.', long_description=LONG_DESC, license='LGPL', From 20f634028dd97b29eee4768a70f5230c3e17b7a5 Mon Sep 17 00:00:00 2001 From: Virgil Dupras Date: Tue, 22 Nov 2016 09:13:18 -0500 Subject: [PATCH 25/99] Convert to single codebase for py2 and py3 No more 2to3. Also, added tox config for easy cross-python testing. --- .gitignore | 3 +- num2words/base.py | 29 ++-- num2words/compat.py | 26 ++++ num2words/lang_DE.py | 10 +- num2words/lang_DK.py | 6 +- num2words/lang_EN.py | 16 ++- num2words/lang_EN_GB.py | 10 +- num2words/lang_ES.py | 8 +- num2words/lang_FR.py | 6 +- num2words/lang_FR_CH.py | 6 +- num2words/lang_ID.py | 8 +- num2words/lang_NO.py | 16 ++- setup.py | 1 - tests/test_pt_BR.py | 312 ++++++++++++++++++++-------------------- tox.ini | 5 + 15 files changed, 256 insertions(+), 206 deletions(-) create mode 100644 num2words/compat.py create mode 100644 tox.ini diff --git a/.gitignore b/.gitignore index f3a9967..d578da0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.pyc build dist -*.egg-info \ No newline at end of file +*.egg-info +/.tox diff --git a/num2words/base.py b/num2words/base.py index 72577b3..272d5bb 100644 --- a/num2words/base.py +++ b/num2words/base.py @@ -15,7 +15,11 @@ # MA 02110-1301 USA from __future__ import unicode_literals + +import math + from .orderedmapping import OrderedMapping +from .compat import to_s class Num2Word_Base(object): @@ -88,7 +92,7 @@ class Num2Word_Base(object): def to_cardinal(self, value): try: - assert long(value) == value + assert int(value) == value except (ValueError, TypeError, AssertionError): return self.to_cardinal_float(value) @@ -113,9 +117,18 @@ class Num2Word_Base(object): except (ValueError, TypeError, AssertionError): raise TypeError(self.errmsg_nonnum % value) + value = float(value) pre = int(value) - post = str(abs(value - pre) * 10**self.precision) - post = '0' * (self.precision - len(post.split('.')[0])) + post + post = abs(value - pre) * 10**self.precision + if abs(round(post) - post) < 0.01: + # We generally floor all values beyond our precision (rather than rounding), but in + # cases where we have something like 1.239999999, which is probably due to python's + # handling of floats, we actually want to consider it as 1.24 instead of 1.23 + post = int(round(post)) + else: + post = int(math.floor(post)) + post = str(post) + post = '0' * (self.precision - len(post)) + post out = [self.to_cardinal(pre)] if self.precision: @@ -123,7 +136,7 @@ class Num2Word_Base(object): for i in range(self.precision): curr = int(post[i]) - out.append(unicode(self.to_cardinal(curr))) + out.append(to_s(self.to_cardinal(curr))) return " ".join(out) @@ -168,10 +181,10 @@ class Num2Word_Base(object): def verify_ordinal(self, value): - if not value == long(value): - raise TypeError, self.errmsg_floatord %(value) + if not value == int(value): + raise TypeError(self.errmsg_floatord % value) if not abs(value) == value: - raise TypeError, self.errmsg_negord %(value) + raise TypeError(self.errmsg_negord % value) def verify_num(self, value): @@ -181,7 +194,7 @@ class Num2Word_Base(object): def set_wordnums(self): pass - + def to_ordinal(self, value): return self.to_cardinal(value) diff --git a/num2words/compat.py b/num2words/compat.py new file mode 100644 index 0000000..7395f4c --- /dev/null +++ b/num2words/compat.py @@ -0,0 +1,26 @@ +# Copyright (c) 2003, Taro Ogawa. All Rights Reserved. +# Copyright (c) 2016, Savoir-faire Linux inc. All Rights Reserved. + +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301 USA + +import sys + +PY3 = sys.version_info[0] == 3 + +def to_s(val): + if PY3: + return str(val) + else: + return unicode(val) + diff --git a/num2words/lang_DE.py b/num2words/lang_DE.py index 252ccb7..1c2fa0f 100644 --- a/num2words/lang_DE.py +++ b/num2words/lang_DE.py @@ -15,7 +15,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA -from __future__ import unicode_literals +from __future__ import unicode_literals, print_function from .lang_EU import Num2Word_EU class Num2Word_DE(Num2Word_EU): @@ -133,10 +133,10 @@ def main(): n2w.test(3000000) n2w.test(3000000000001) n2w.test(3000000324566) - print n2w.to_currency(112121) - print n2w.to_year(2000) - print n2w.to_year(1820) - print n2w.to_year(2001) + print(n2w.to_currency(112121)) + print(n2w.to_year(2000)) + print(n2w.to_year(1820)) + print(n2w.to_year(2001)) if __name__ == "__main__": main() diff --git a/num2words/lang_DK.py b/num2words/lang_DK.py index bc88c06..64cf793 100644 --- a/num2words/lang_DK.py +++ b/num2words/lang_DK.py @@ -14,7 +14,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA -from __future__ import division, unicode_literals +from __future__ import division, unicode_literals, print_function from num2words import lang_EU class Num2Word_DK(lang_EU.Num2Word_EU): @@ -146,8 +146,8 @@ def main(): n2w.test(val) n2w.test(1325325436067876801768700107601001012212132143210473207540327057320957032975032975093275093275093270957329057320975093272950730) for val in [1,120, 160, 1000,1120,1800, 1976,2000,2010,2099,2171]: - print val, "er", n2w.to_currency(val) - print val, "er", n2w.to_year(val) + print(val, "er", n2w.to_currency(val)) + print(val, "er", n2w.to_year(val)) n2w.test(65132) if __name__ == "__main__": diff --git a/num2words/lang_EN.py b/num2words/lang_EN.py index 54646f5..656abfc 100644 --- a/num2words/lang_EN.py +++ b/num2words/lang_EN.py @@ -14,7 +14,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA -from __future__ import division, unicode_literals +from __future__ import division, unicode_literals, print_function from . import lang_EU class Num2Word_EN(lang_EU.Num2Word_EU): @@ -47,7 +47,9 @@ class Num2Word_EN(lang_EU.Num2Word_EU): "twelve" : "twelfth" } - def merge(self, (ltext, lnum), (rtext, rnum)): + def merge(self, lpair, rpair): + ltext, lnum = lpair + rtext, rnum = rpair if lnum == 1 and rnum < 100: return (rtext, rnum) elif 100 > lnum > rnum : @@ -68,9 +70,9 @@ class Num2Word_EN(lang_EU.Num2Word_EU): lastword = self.ords[lastword] except KeyError: if lastword[-1] == "y": - lastword = lastword[:-1] + "ie" + lastword = lastword[:-1] + "ie" lastword += "th" - lastwords[-1] = self.title(lastword) + lastwords[-1] = self.title(lastword) outwords[-1] = "-".join(lastwords) return " ".join(outwords) @@ -105,9 +107,9 @@ def main(): n2w.test(val) n2w.test(1325325436067876801768700107601001012212132143210473207540327057320957032975032975093275093275093270957329057320975093272950730) for val in [1,120,1000,1120,1800, 1976,2000,2010,2099,2171]: - print val, "is", n2w.to_currency(val) - print val, "is", n2w.to_year(val) - + print(val, "is", n2w.to_currency(val)) + print(val, "is", n2w.to_year(val)) + if __name__ == "__main__": main() diff --git a/num2words/lang_EN_GB.py b/num2words/lang_EN_GB.py index 568594d..a01c41a 100644 --- a/num2words/lang_EN_GB.py +++ b/num2words/lang_EN_GB.py @@ -14,10 +14,10 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA -from __future__ import unicode_literals +from __future__ import unicode_literals, print_function from .lang_EN import Num2Word_EN - + class Num2Word_EN_GB(Num2Word_EN): def to_currency(self, val, longval=True): return self.to_splitnum(val, hightxt="pound/s", lowtxt="pence", @@ -38,9 +38,9 @@ def main(): n2w.test(val) n2w.test(1325325436067876801768700107601001012212132143210473207540327057320957032975032975093275093275093270957329057320975093272950730) for val in [1,120,1000,1120,1800, 1976,2000,2010,2099,2171]: - print val, "is", n2w.to_currency(val) - print val, "is", n2w.to_year(val) - + print(val, "is", n2w.to_currency(val)) + print(val, "is", n2w.to_year(val)) + if __name__ == "__main__": main() diff --git a/num2words/lang_ES.py b/num2words/lang_ES.py index 71103a8..c010d52 100644 --- a/num2words/lang_ES.py +++ b/num2words/lang_ES.py @@ -16,7 +16,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA -from __future__ import unicode_literals +from __future__ import unicode_literals, print_function from .lang_EU import Num2Word_EU class Num2Word_ES(Num2Word_EU): @@ -173,9 +173,9 @@ def main(): n2w.test(val) n2w.test(1325325436067876801768700107601001012212132143210473207540327057320957032975032975093275093275093270957329057320975093272950730) - print n2w.to_currency(1222) - print n2w.to_currency(1222, old=True) - print n2w.to_year(1222) + print(n2w.to_currency(1222)) + print(n2w.to_currency(1222, old=True)) + print(n2w.to_year(1222)) if __name__ == "__main__": main() diff --git a/num2words/lang_FR.py b/num2words/lang_FR.py index a4e0f6a..1209eab 100644 --- a/num2words/lang_FR.py +++ b/num2words/lang_FR.py @@ -15,7 +15,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA -from __future__ import unicode_literals +from __future__ import unicode_literals, print_function from .lang_EU import Num2Word_EU @@ -106,8 +106,8 @@ def main(): n2w.test(val) n2w.test(1325325436067876801768700107601001012212132143210473207540327057320957032975032975093275093275093270957329057320975093272950730) - print n2w.to_currency(112121) - print n2w.to_year(1996) + print(n2w.to_currency(112121)) + print(n2w.to_year(1996)) if __name__ == "__main__": diff --git a/num2words/lang_FR_CH.py b/num2words/lang_FR_CH.py index b2130eb..b6d40a0 100644 --- a/num2words/lang_FR_CH.py +++ b/num2words/lang_FR_CH.py @@ -15,7 +15,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA -from __future__ import unicode_literals +from __future__ import unicode_literals, print_function from .lang_EU import Num2Word_EU class Num2Word_FR_CH(Num2Word_EU): @@ -101,8 +101,8 @@ def main(): n2w.test(val) n2w.test(1325325436067876801768700107601001012212132143210473207540327057320957032975032975093275093275093270957329057320975093272950730) - print n2w.to_currency(112121) - print n2w.to_year(1996) + print(n2w.to_currency(112121)) + print(n2w.to_year(1996)) if __name__ == "__main__": diff --git a/num2words/lang_ID.py b/num2words/lang_ID.py index ee07065..9437db7 100644 --- a/num2words/lang_ID.py +++ b/num2words/lang_ID.py @@ -14,6 +14,8 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA +from __future__ import unicode_literals, print_function + class Num2Word_ID(): BASE = {0: [], @@ -188,7 +190,7 @@ class Num2Word_ID(): return self.to_cardinal(value) def verify_ordinal(self, value): - if not value == long(value): - raise TypeError, self.errmsg_floatord %(value) + if not value == int(value): + raise TypeError(self.errmsg_floatord % value) if not abs(value) == value: - raise TypeError, self.errmsg_negord %(value) + raise TypeError(self.errmsg_negord % value) diff --git a/num2words/lang_NO.py b/num2words/lang_NO.py index 273622b..2c744e1 100644 --- a/num2words/lang_NO.py +++ b/num2words/lang_NO.py @@ -14,7 +14,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA -from __future__ import division, unicode_literals +from __future__ import division, unicode_literals, print_function from . import lang_EU class Num2Word_NO(lang_EU.Num2Word_EU): @@ -54,7 +54,9 @@ class Num2Word_NO(lang_EU.Num2Word_EU): "tjue" : "tjuende" } - def merge(self, (ltext, lnum), (rtext, rnum)): + def merge(self, lpair, rpair): + ltext, lnum = lpair + rtext, rnum = rpair if lnum == 1 and rnum < 100: return (rtext, rnum) elif 100 > lnum > rnum : @@ -75,10 +77,10 @@ class Num2Word_NO(lang_EU.Num2Word_EU): lastword = self.ords[lastword] except KeyError: if lastword[-2:] == "ti": - lastword = lastword + "ende" + lastword = lastword + "ende" else: lastword += "de" - lastwords[-1] = self.title(lastword) + lastwords[-1] = self.title(lastword) outwords[-1] = "".join(lastwords) return " ".join(outwords) @@ -113,9 +115,9 @@ def main(): n2w.test(val) n2w.test(1325325436067876801768700107601001012212132143210473207540327057320957032975032975093275093275093270957329057320975093272950730) for val in [1,120,1000,1120,1800, 1976,2000,2010,2099,2171]: - print val, "er", n2w.to_currency(val) - print val, "er", n2w.to_year(val) - + print(val, "er", n2w.to_currency(val)) + print(val, "er", n2w.to_year(val)) + if __name__ == "__main__": main() diff --git a/setup.py b/setup.py index b842523..ab6aaf2 100644 --- a/setup.py +++ b/setup.py @@ -29,5 +29,4 @@ setup( url='https://github.com/savoirfairelinux/num2words', packages=find_packages(exclude=['tests']), test_suite='tests', - use_2to3=True, ) diff --git a/tests/test_pt_BR.py b/tests/test_pt_BR.py index 9a82481..a681d91 100644 --- a/tests/test_pt_BR.py +++ b/tests/test_pt_BR.py @@ -29,191 +29,191 @@ class Num2WordsPTBRTest(TestCase): self.n2w = Num2Word_PT_BR() def test_cardinal_integer(self): - self.assertEquals(num2words(1, lang='pt_BR'), 'um') - self.assertEquals(num2words(2, lang='pt_BR'), 'dois') - self.assertEquals(num2words(3, lang='pt_BR'), 'três') - self.assertEquals(num2words(4, lang='pt_BR'), 'quatro') - self.assertEquals(num2words(5, lang='pt_BR'), 'cinco') - self.assertEquals(num2words(6, lang='pt_BR'), 'seis') - self.assertEquals(num2words(7, lang='pt_BR'), 'sete') - self.assertEquals(num2words(8, lang='pt_BR'), 'oito') - self.assertEquals(num2words(9, lang='pt_BR'), 'nove') - self.assertEquals(num2words(10, lang='pt_BR'), 'dez') - self.assertEquals(num2words(11, lang='pt_BR'), 'onze') - self.assertEquals(num2words(12, lang='pt_BR'), 'doze') - self.assertEquals(num2words(13, lang='pt_BR'), 'treze') - self.assertEquals(num2words(14, lang='pt_BR'), 'catorze') - self.assertEquals(num2words(15, lang='pt_BR'), 'quinze') - self.assertEquals(num2words(16, lang='pt_BR'), 'dezesseis') - self.assertEquals(num2words(17, lang='pt_BR'), 'dezessete') - self.assertEquals(num2words(18, lang='pt_BR'), 'dezoito') - self.assertEquals(num2words(19, lang='pt_BR'), 'dezenove') - self.assertEquals(num2words(20, lang='pt_BR'), 'vinte') + self.assertEqual(num2words(1, lang='pt_BR'), 'um') + self.assertEqual(num2words(2, lang='pt_BR'), 'dois') + self.assertEqual(num2words(3, lang='pt_BR'), 'três') + self.assertEqual(num2words(4, lang='pt_BR'), 'quatro') + self.assertEqual(num2words(5, lang='pt_BR'), 'cinco') + self.assertEqual(num2words(6, lang='pt_BR'), 'seis') + self.assertEqual(num2words(7, lang='pt_BR'), 'sete') + self.assertEqual(num2words(8, lang='pt_BR'), 'oito') + self.assertEqual(num2words(9, lang='pt_BR'), 'nove') + self.assertEqual(num2words(10, lang='pt_BR'), 'dez') + self.assertEqual(num2words(11, lang='pt_BR'), 'onze') + self.assertEqual(num2words(12, lang='pt_BR'), 'doze') + self.assertEqual(num2words(13, lang='pt_BR'), 'treze') + self.assertEqual(num2words(14, lang='pt_BR'), 'catorze') + self.assertEqual(num2words(15, lang='pt_BR'), 'quinze') + self.assertEqual(num2words(16, lang='pt_BR'), 'dezesseis') + self.assertEqual(num2words(17, lang='pt_BR'), 'dezessete') + self.assertEqual(num2words(18, lang='pt_BR'), 'dezoito') + self.assertEqual(num2words(19, lang='pt_BR'), 'dezenove') + self.assertEqual(num2words(20, lang='pt_BR'), 'vinte') - self.assertEquals(num2words(21, lang='pt_BR'), 'vinte e um') - self.assertEquals(num2words(22, lang='pt_BR'), 'vinte e dois') - self.assertEquals(num2words(35, lang='pt_BR'), 'trinta e cinco') - self.assertEquals(num2words(99, lang='pt_BR'), 'noventa e nove') + self.assertEqual(num2words(21, lang='pt_BR'), 'vinte e um') + self.assertEqual(num2words(22, lang='pt_BR'), 'vinte e dois') + self.assertEqual(num2words(35, lang='pt_BR'), 'trinta e cinco') + self.assertEqual(num2words(99, lang='pt_BR'), 'noventa e nove') - self.assertEquals(num2words(100, lang='pt_BR'), 'cem') - self.assertEquals(num2words(101, lang='pt_BR'), 'cento e um') - self.assertEquals(num2words(128, lang='pt_BR'), 'cento e vinte e oito') - self.assertEquals(num2words(713, lang='pt_BR'), 'setecentos e treze') + self.assertEqual(num2words(100, lang='pt_BR'), 'cem') + self.assertEqual(num2words(101, lang='pt_BR'), 'cento e um') + self.assertEqual(num2words(128, lang='pt_BR'), 'cento e vinte e oito') + self.assertEqual(num2words(713, lang='pt_BR'), 'setecentos e treze') - self.assertEquals(num2words(1000, lang='pt_BR'), 'mil') - self.assertEquals(num2words(1001, lang='pt_BR'), 'mil e um') - self.assertEquals(num2words(1111, lang='pt_BR'), 'mil, cento e onze') - self.assertEquals(num2words(2114, lang='pt_BR'), 'dois mil, cento e catorze') - self.assertEquals(num2words(73421, lang='pt_BR'), 'setenta e três mil, quatrocentos e vinte e um') + self.assertEqual(num2words(1000, lang='pt_BR'), 'mil') + self.assertEqual(num2words(1001, lang='pt_BR'), 'mil e um') + self.assertEqual(num2words(1111, lang='pt_BR'), 'mil, cento e onze') + self.assertEqual(num2words(2114, lang='pt_BR'), 'dois mil, cento e catorze') + self.assertEqual(num2words(73421, lang='pt_BR'), 'setenta e três mil, quatrocentos e vinte e um') - self.assertEquals(num2words(100000, lang='pt_BR'), 'cem mil') - self.assertEquals(num2words(250050, lang='pt_BR'), 'duzentos e cinquenta mil e cinquenta') - self.assertEquals(num2words(6000000, lang='pt_BR'), 'seis milhões') - self.assertEquals(num2words(19000000000, lang='pt_BR'), 'dezenove bilhões') - self.assertEquals(num2words(145000000002, lang='pt_BR'), 'cento e quarenta e cinco bilhões e dois') + self.assertEqual(num2words(100000, lang='pt_BR'), 'cem mil') + self.assertEqual(num2words(250050, lang='pt_BR'), 'duzentos e cinquenta mil e cinquenta') + self.assertEqual(num2words(6000000, lang='pt_BR'), 'seis milhões') + self.assertEqual(num2words(19000000000, lang='pt_BR'), 'dezenove bilhões') + self.assertEqual(num2words(145000000002, lang='pt_BR'), 'cento e quarenta e cinco bilhões e dois') def test_cardinal_integer_negative(self): - self.assertEquals(num2words(-1, lang='pt_BR'), 'menos um') - self.assertEquals(num2words(-256, lang='pt_BR'), 'menos duzentos e cinquenta e seis') - self.assertEquals(num2words(-1000, lang='pt_BR'), 'menos mil') - self.assertEquals(num2words(-1000000, lang='pt_BR'), 'menos um milhão') - self.assertEquals(num2words(-1234567, lang='pt_BR'), 'menos um milhão, duzentos e trinta e quatro mil, quinhentos e sessenta e sete') + self.assertEqual(num2words(-1, lang='pt_BR'), 'menos um') + self.assertEqual(num2words(-256, lang='pt_BR'), 'menos duzentos e cinquenta e seis') + self.assertEqual(num2words(-1000, lang='pt_BR'), 'menos mil') + self.assertEqual(num2words(-1000000, lang='pt_BR'), 'menos um milhão') + self.assertEqual(num2words(-1234567, lang='pt_BR'), 'menos um milhão, duzentos e trinta e quatro mil, quinhentos e sessenta e sete') def test_cardinal_float(self): - self.assertEquals(num2words(Decimal('1.00'), lang='pt_BR'), 'um') - self.assertEquals(num2words(Decimal('1.01'), lang='pt_BR'), 'um vírgula zero um') - self.assertEquals(num2words(Decimal('1.035'), lang='pt_BR'), 'um vírgula zero três') - self.assertEquals(num2words(Decimal('1.35'), lang='pt_BR'), 'um vírgula três cinco') - self.assertEquals(num2words(Decimal('3.14159'), lang='pt_BR'), 'três vírgula um quatro') - self.assertEquals(num2words(Decimal('101.22'), lang='pt_BR'), 'cento e um vírgula dois dois') - self.assertEquals(num2words(Decimal('2345.75'), lang='pt_BR'), 'dois mil, trezentos e quarenta e cinco vírgula sete cinco') + self.assertEqual(num2words(Decimal('1.00'), lang='pt_BR'), 'um') + self.assertEqual(num2words(Decimal('1.01'), lang='pt_BR'), 'um vírgula zero um') + self.assertEqual(num2words(Decimal('1.035'), lang='pt_BR'), 'um vírgula zero três') + self.assertEqual(num2words(Decimal('1.35'), lang='pt_BR'), 'um vírgula três cinco') + self.assertEqual(num2words(Decimal('3.14159'), lang='pt_BR'), 'três vírgula um quatro') + self.assertEqual(num2words(Decimal('101.22'), lang='pt_BR'), 'cento e um vírgula dois dois') + self.assertEqual(num2words(Decimal('2345.75'), lang='pt_BR'), 'dois mil, trezentos e quarenta e cinco vírgula sete cinco') def test_cardinal_float_negative(self): - self.assertEquals(num2words(Decimal('-2.34'), lang='pt_BR'), 'menos dois vírgula três quatro') - self.assertEquals(num2words(Decimal('-9.99'), lang='pt_BR'), 'menos nove vírgula nove nove') - self.assertEquals(num2words(Decimal('-7.01'), lang='pt_BR'), 'menos sete vírgula zero um') - self.assertEquals(num2words(Decimal('-222.22'), lang='pt_BR'), 'menos duzentos e vinte e dois vírgula dois dois') + self.assertEqual(num2words(Decimal('-2.34'), lang='pt_BR'), 'menos dois vírgula três quatro') + self.assertEqual(num2words(Decimal('-9.99'), lang='pt_BR'), 'menos nove vírgula nove nove') + self.assertEqual(num2words(Decimal('-7.01'), lang='pt_BR'), 'menos sete vírgula zero um') + self.assertEqual(num2words(Decimal('-222.22'), lang='pt_BR'), 'menos duzentos e vinte e dois vírgula dois dois') def test_ordinal(self): - self.assertEquals(num2words(1, lang='pt_BR', ordinal=True), 'primeiro') - self.assertEquals(num2words(2, lang='pt_BR', ordinal=True), 'segundo') - self.assertEquals(num2words(3, lang='pt_BR', ordinal=True), 'terceiro') - self.assertEquals(num2words(4, lang='pt_BR', ordinal=True), 'quarto') - self.assertEquals(num2words(5, lang='pt_BR', ordinal=True), 'quinto') - self.assertEquals(num2words(6, lang='pt_BR', ordinal=True), 'sexto') - self.assertEquals(num2words(7, lang='pt_BR', ordinal=True), 'sétimo') - self.assertEquals(num2words(8, lang='pt_BR', ordinal=True), 'oitavo') - self.assertEquals(num2words(9, lang='pt_BR', ordinal=True), 'nono') - self.assertEquals(num2words(10, lang='pt_BR', ordinal=True), 'décimo') - self.assertEquals(num2words(11, lang='pt_BR', ordinal=True), 'décimo primeiro') - self.assertEquals(num2words(12, lang='pt_BR', ordinal=True), 'décimo segundo') - self.assertEquals(num2words(13, lang='pt_BR', ordinal=True), 'décimo terceiro') - self.assertEquals(num2words(14, lang='pt_BR', ordinal=True), 'décimo quarto') - self.assertEquals(num2words(15, lang='pt_BR', ordinal=True), 'décimo quinto') - self.assertEquals(num2words(16, lang='pt_BR', ordinal=True), 'décimo sexto') - self.assertEquals(num2words(17, lang='pt_BR', ordinal=True), 'décimo sétimo') - self.assertEquals(num2words(18, lang='pt_BR', ordinal=True), 'décimo oitavo') - self.assertEquals(num2words(19, lang='pt_BR', ordinal=True), 'décimo nono') - self.assertEquals(num2words(20, lang='pt_BR', ordinal=True), 'vigésimo') + self.assertEqual(num2words(1, lang='pt_BR', ordinal=True), 'primeiro') + self.assertEqual(num2words(2, lang='pt_BR', ordinal=True), 'segundo') + self.assertEqual(num2words(3, lang='pt_BR', ordinal=True), 'terceiro') + self.assertEqual(num2words(4, lang='pt_BR', ordinal=True), 'quarto') + self.assertEqual(num2words(5, lang='pt_BR', ordinal=True), 'quinto') + self.assertEqual(num2words(6, lang='pt_BR', ordinal=True), 'sexto') + self.assertEqual(num2words(7, lang='pt_BR', ordinal=True), 'sétimo') + self.assertEqual(num2words(8, lang='pt_BR', ordinal=True), 'oitavo') + self.assertEqual(num2words(9, lang='pt_BR', ordinal=True), 'nono') + self.assertEqual(num2words(10, lang='pt_BR', ordinal=True), 'décimo') + self.assertEqual(num2words(11, lang='pt_BR', ordinal=True), 'décimo primeiro') + self.assertEqual(num2words(12, lang='pt_BR', ordinal=True), 'décimo segundo') + self.assertEqual(num2words(13, lang='pt_BR', ordinal=True), 'décimo terceiro') + self.assertEqual(num2words(14, lang='pt_BR', ordinal=True), 'décimo quarto') + self.assertEqual(num2words(15, lang='pt_BR', ordinal=True), 'décimo quinto') + self.assertEqual(num2words(16, lang='pt_BR', ordinal=True), 'décimo sexto') + self.assertEqual(num2words(17, lang='pt_BR', ordinal=True), 'décimo sétimo') + self.assertEqual(num2words(18, lang='pt_BR', ordinal=True), 'décimo oitavo') + self.assertEqual(num2words(19, lang='pt_BR', ordinal=True), 'décimo nono') + self.assertEqual(num2words(20, lang='pt_BR', ordinal=True), 'vigésimo') - self.assertEquals(num2words(21, lang='pt_BR', ordinal=True), 'vigésimo primeiro') - self.assertEquals(num2words(22, lang='pt_BR', ordinal=True), 'vigésimo segundo') - self.assertEquals(num2words(35, lang='pt_BR', ordinal=True), 'trigésimo quinto') - self.assertEquals(num2words(99, lang='pt_BR', ordinal=True), 'nonagésimo nono') + self.assertEqual(num2words(21, lang='pt_BR', ordinal=True), 'vigésimo primeiro') + self.assertEqual(num2words(22, lang='pt_BR', ordinal=True), 'vigésimo segundo') + self.assertEqual(num2words(35, lang='pt_BR', ordinal=True), 'trigésimo quinto') + self.assertEqual(num2words(99, lang='pt_BR', ordinal=True), 'nonagésimo nono') - self.assertEquals(num2words(100, lang='pt_BR', ordinal=True), 'centésimo') - self.assertEquals(num2words(101, lang='pt_BR', ordinal=True), 'centésimo primeiro') - self.assertEquals(num2words(128, lang='pt_BR', ordinal=True), 'centésimo vigésimo oitavo') - self.assertEquals(num2words(713, lang='pt_BR', ordinal=True), 'septigentésimo décimo terceiro') + self.assertEqual(num2words(100, lang='pt_BR', ordinal=True), 'centésimo') + self.assertEqual(num2words(101, lang='pt_BR', ordinal=True), 'centésimo primeiro') + self.assertEqual(num2words(128, lang='pt_BR', ordinal=True), 'centésimo vigésimo oitavo') + self.assertEqual(num2words(713, lang='pt_BR', ordinal=True), 'septigentésimo décimo terceiro') - self.assertEquals(num2words(1000, lang='pt_BR', ordinal=True), 'milésimo') - self.assertEquals(num2words(1001, lang='pt_BR', ordinal=True), 'milésimo primeiro') - self.assertEquals(num2words(1111, lang='pt_BR', ordinal=True), 'milésimo centésimo décimo primeiro') - self.assertEquals(num2words(2114, lang='pt_BR', ordinal=True), 'segundo milésimo centésimo décimo quarto') - self.assertEquals(num2words(73421, lang='pt_BR', ordinal=True), 'septuagésimo terceiro milésimo quadrigentésimo vigésimo primeiro') + self.assertEqual(num2words(1000, lang='pt_BR', ordinal=True), 'milésimo') + self.assertEqual(num2words(1001, lang='pt_BR', ordinal=True), 'milésimo primeiro') + self.assertEqual(num2words(1111, lang='pt_BR', ordinal=True), 'milésimo centésimo décimo primeiro') + self.assertEqual(num2words(2114, lang='pt_BR', ordinal=True), 'segundo milésimo centésimo décimo quarto') + self.assertEqual(num2words(73421, lang='pt_BR', ordinal=True), 'septuagésimo terceiro milésimo quadrigentésimo vigésimo primeiro') - self.assertEquals(num2words(100000, lang='pt_BR', ordinal=True), 'centésimo milésimo') - self.assertEquals(num2words(250050, lang='pt_BR', ordinal=True), 'ducentésimo quinquagésimo milésimo quinquagésimo') - self.assertEquals(num2words(6000000, lang='pt_BR', ordinal=True), 'sexto milionésimo') - self.assertEquals(num2words(19000000000, lang='pt_BR', ordinal=True), 'décimo nono bilionésimo') - self.assertEquals(num2words(145000000002, lang='pt_BR', ordinal=True), 'centésimo quadragésimo quinto bilionésimo segundo') + self.assertEqual(num2words(100000, lang='pt_BR', ordinal=True), 'centésimo milésimo') + self.assertEqual(num2words(250050, lang='pt_BR', ordinal=True), 'ducentésimo quinquagésimo milésimo quinquagésimo') + self.assertEqual(num2words(6000000, lang='pt_BR', ordinal=True), 'sexto milionésimo') + self.assertEqual(num2words(19000000000, lang='pt_BR', ordinal=True), 'décimo nono bilionésimo') + self.assertEqual(num2words(145000000002, lang='pt_BR', ordinal=True), 'centésimo quadragésimo quinto bilionésimo segundo') def test_currency_integer(self): - self.assertEquals(self.n2w.to_currency(1), 'um real') - self.assertEquals(self.n2w.to_currency(2), 'dois reais') - self.assertEquals(self.n2w.to_currency(3), 'três reais') - self.assertEquals(self.n2w.to_currency(4), 'quatro reais') - self.assertEquals(self.n2w.to_currency(5), 'cinco reais') - self.assertEquals(self.n2w.to_currency(6), 'seis reais') - self.assertEquals(self.n2w.to_currency(7), 'sete reais') - self.assertEquals(self.n2w.to_currency(8), 'oito reais') - self.assertEquals(self.n2w.to_currency(9), 'nove reais') - self.assertEquals(self.n2w.to_currency(10), 'dez reais') - self.assertEquals(self.n2w.to_currency(11), 'onze reais') - self.assertEquals(self.n2w.to_currency(12), 'doze reais') - self.assertEquals(self.n2w.to_currency(13), 'treze reais') - self.assertEquals(self.n2w.to_currency(14), 'catorze reais') - self.assertEquals(self.n2w.to_currency(15), 'quinze reais') - self.assertEquals(self.n2w.to_currency(16), 'dezesseis reais') - self.assertEquals(self.n2w.to_currency(17), 'dezessete reais') - self.assertEquals(self.n2w.to_currency(18), 'dezoito reais') - self.assertEquals(self.n2w.to_currency(19), 'dezenove reais') - self.assertEquals(self.n2w.to_currency(20), 'vinte reais') + self.assertEqual(self.n2w.to_currency(1), 'um real') + self.assertEqual(self.n2w.to_currency(2), 'dois reais') + self.assertEqual(self.n2w.to_currency(3), 'três reais') + self.assertEqual(self.n2w.to_currency(4), 'quatro reais') + self.assertEqual(self.n2w.to_currency(5), 'cinco reais') + self.assertEqual(self.n2w.to_currency(6), 'seis reais') + self.assertEqual(self.n2w.to_currency(7), 'sete reais') + self.assertEqual(self.n2w.to_currency(8), 'oito reais') + self.assertEqual(self.n2w.to_currency(9), 'nove reais') + self.assertEqual(self.n2w.to_currency(10), 'dez reais') + self.assertEqual(self.n2w.to_currency(11), 'onze reais') + self.assertEqual(self.n2w.to_currency(12), 'doze reais') + self.assertEqual(self.n2w.to_currency(13), 'treze reais') + self.assertEqual(self.n2w.to_currency(14), 'catorze reais') + self.assertEqual(self.n2w.to_currency(15), 'quinze reais') + self.assertEqual(self.n2w.to_currency(16), 'dezesseis reais') + self.assertEqual(self.n2w.to_currency(17), 'dezessete reais') + self.assertEqual(self.n2w.to_currency(18), 'dezoito reais') + self.assertEqual(self.n2w.to_currency(19), 'dezenove reais') + self.assertEqual(self.n2w.to_currency(20), 'vinte reais') - self.assertEquals(self.n2w.to_currency(21), 'vinte e um reais') - self.assertEquals(self.n2w.to_currency(22), 'vinte e dois reais') - self.assertEquals(self.n2w.to_currency(35), 'trinta e cinco reais') - self.assertEquals(self.n2w.to_currency(99), 'noventa e nove reais') + self.assertEqual(self.n2w.to_currency(21), 'vinte e um reais') + self.assertEqual(self.n2w.to_currency(22), 'vinte e dois reais') + self.assertEqual(self.n2w.to_currency(35), 'trinta e cinco reais') + self.assertEqual(self.n2w.to_currency(99), 'noventa e nove reais') - self.assertEquals(self.n2w.to_currency(100), 'cem reais') - self.assertEquals(self.n2w.to_currency(101), 'cento e um reais') - self.assertEquals(self.n2w.to_currency(128), 'cento e vinte e oito reais') - self.assertEquals(self.n2w.to_currency(713), 'setecentos e treze reais') + self.assertEqual(self.n2w.to_currency(100), 'cem reais') + self.assertEqual(self.n2w.to_currency(101), 'cento e um reais') + self.assertEqual(self.n2w.to_currency(128), 'cento e vinte e oito reais') + self.assertEqual(self.n2w.to_currency(713), 'setecentos e treze reais') - self.assertEquals(self.n2w.to_currency(1000), 'mil reais') - self.assertEquals(self.n2w.to_currency(1001), 'mil e um reais') - self.assertEquals(self.n2w.to_currency(1111), 'mil, cento e onze reais') - self.assertEquals(self.n2w.to_currency(2114), 'dois mil, cento e catorze reais') - self.assertEquals(self.n2w.to_currency(73421), 'setenta e três mil, quatrocentos e vinte e um reais') + self.assertEqual(self.n2w.to_currency(1000), 'mil reais') + self.assertEqual(self.n2w.to_currency(1001), 'mil e um reais') + self.assertEqual(self.n2w.to_currency(1111), 'mil, cento e onze reais') + self.assertEqual(self.n2w.to_currency(2114), 'dois mil, cento e catorze reais') + self.assertEqual(self.n2w.to_currency(73421), 'setenta e três mil, quatrocentos e vinte e um reais') - self.assertEquals(self.n2w.to_currency(100000), 'cem mil reais') - self.assertEquals(self.n2w.to_currency(250050), 'duzentos e cinquenta mil e cinquenta reais') - self.assertEquals(self.n2w.to_currency(6000000), 'seis milhões de reais') - self.assertEquals(self.n2w.to_currency(19000000000), 'dezenove bilhões de reais') - self.assertEquals(self.n2w.to_currency(145000000002), 'cento e quarenta e cinco bilhões e dois reais') + self.assertEqual(self.n2w.to_currency(100000), 'cem mil reais') + self.assertEqual(self.n2w.to_currency(250050), 'duzentos e cinquenta mil e cinquenta reais') + self.assertEqual(self.n2w.to_currency(6000000), 'seis milhões de reais') + self.assertEqual(self.n2w.to_currency(19000000000), 'dezenove bilhões de reais') + self.assertEqual(self.n2w.to_currency(145000000002), 'cento e quarenta e cinco bilhões e dois reais') def test_currency_integer_negative(self): - self.assertEquals(self.n2w.to_currency(-1), 'menos um real') - self.assertEquals(self.n2w.to_currency(-256), 'menos duzentos e cinquenta e seis reais') - self.assertEquals(self.n2w.to_currency(-1000), 'menos mil reais') - self.assertEquals(self.n2w.to_currency(-1000000), 'menos um milhão de reais') - self.assertEquals(self.n2w.to_currency(-1234567), 'menos um milhão, duzentos e trinta e quatro mil, quinhentos e sessenta e sete reais') + self.assertEqual(self.n2w.to_currency(-1), 'menos um real') + self.assertEqual(self.n2w.to_currency(-256), 'menos duzentos e cinquenta e seis reais') + self.assertEqual(self.n2w.to_currency(-1000), 'menos mil reais') + self.assertEqual(self.n2w.to_currency(-1000000), 'menos um milhão de reais') + self.assertEqual(self.n2w.to_currency(-1234567), 'menos um milhão, duzentos e trinta e quatro mil, quinhentos e sessenta e sete reais') def test_currency_float(self): - self.assertEquals(self.n2w.to_currency(Decimal('1.00')), 'um real') - self.assertEquals(self.n2w.to_currency(Decimal('1.01')), 'um real e um centavo') - self.assertEquals(self.n2w.to_currency(Decimal('1.035')), 'um real e três centavos') - self.assertEquals(self.n2w.to_currency(Decimal('1.35')), 'um real e trinta e cinco centavos') - self.assertEquals(self.n2w.to_currency(Decimal('3.14159')), 'três reais e catorze centavos') - self.assertEquals(self.n2w.to_currency(Decimal('101.22')), 'cento e um reais e vinte e dois centavos') - self.assertEquals(self.n2w.to_currency(Decimal('2345.75')), 'dois mil, trezentos e quarenta e cinco reais e setenta e cinco centavos') + self.assertEqual(self.n2w.to_currency(Decimal('1.00')), 'um real') + self.assertEqual(self.n2w.to_currency(Decimal('1.01')), 'um real e um centavo') + self.assertEqual(self.n2w.to_currency(Decimal('1.035')), 'um real e três centavos') + self.assertEqual(self.n2w.to_currency(Decimal('1.35')), 'um real e trinta e cinco centavos') + self.assertEqual(self.n2w.to_currency(Decimal('3.14159')), 'três reais e catorze centavos') + self.assertEqual(self.n2w.to_currency(Decimal('101.22')), 'cento e um reais e vinte e dois centavos') + self.assertEqual(self.n2w.to_currency(Decimal('2345.75')), 'dois mil, trezentos e quarenta e cinco reais e setenta e cinco centavos') def test_currency_float_negative(self): - self.assertEquals(self.n2w.to_currency(Decimal('-2.34')), 'menos dois reais e trinta e quatro centavos') - self.assertEquals(self.n2w.to_currency(Decimal('-9.99')), 'menos nove reais e noventa e nove centavos') - self.assertEquals(self.n2w.to_currency(Decimal('-7.01')), 'menos sete reais e um centavo') - self.assertEquals(self.n2w.to_currency(Decimal('-222.22')), 'menos duzentos e vinte e dois reais e vinte e dois centavos') + self.assertEqual(self.n2w.to_currency(Decimal('-2.34')), 'menos dois reais e trinta e quatro centavos') + self.assertEqual(self.n2w.to_currency(Decimal('-9.99')), 'menos nove reais e noventa e nove centavos') + self.assertEqual(self.n2w.to_currency(Decimal('-7.01')), 'menos sete reais e um centavo') + self.assertEqual(self.n2w.to_currency(Decimal('-222.22')), 'menos duzentos e vinte e dois reais e vinte e dois centavos') def test_year(self): - self.assertEquals(self.n2w.to_year(1001), 'mil e um') - self.assertEquals(self.n2w.to_year(1789), 'mil, setecentos e oitenta e nove') - self.assertEquals(self.n2w.to_year(1942), 'mil, novecentos e quarenta e dois') - self.assertEquals(self.n2w.to_year(1984), 'mil, novecentos e oitenta e quatro') - self.assertEquals(self.n2w.to_year(2000), 'dois mil') - self.assertEquals(self.n2w.to_year(2001), 'dois mil e um') - self.assertEquals(self.n2w.to_year(2016), 'dois mil e dezesseis') + self.assertEqual(self.n2w.to_year(1001), 'mil e um') + self.assertEqual(self.n2w.to_year(1789), 'mil, setecentos e oitenta e nove') + self.assertEqual(self.n2w.to_year(1942), 'mil, novecentos e quarenta e dois') + self.assertEqual(self.n2w.to_year(1984), 'mil, novecentos e oitenta e quatro') + self.assertEqual(self.n2w.to_year(2000), 'dois mil') + self.assertEqual(self.n2w.to_year(2001), 'dois mil e um') + self.assertEqual(self.n2w.to_year(2016), 'dois mil e dezesseis') def test_year_negative(self): - self.assertEquals(self.n2w.to_year(-30), 'trinta antes de Cristo') - self.assertEquals(self.n2w.to_year(-744), 'setecentos e quarenta e quatro antes de Cristo') - self.assertEquals(self.n2w.to_year(-10000), 'dez mil antes de Cristo') + self.assertEqual(self.n2w.to_year(-30), 'trinta antes de Cristo') + self.assertEqual(self.n2w.to_year(-744), 'setecentos e quarenta e quatro antes de Cristo') + self.assertEqual(self.n2w.to_year(-10000), 'dez mil antes de Cristo') diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..13bca3c --- /dev/null +++ b/tox.ini @@ -0,0 +1,5 @@ +[tox] +envlist = py27,py34 + +[testenv] +commands = python -m unittest discover From 182b82cf1ff47d588f50b1feb650e721626cbbd1 Mon Sep 17 00:00:00 2001 From: Noah Santacruz Date: Tue, 22 Nov 2016 10:23:15 -0500 Subject: [PATCH 26/99] Added Hebrew ordinal numbers #54 Squashed commit of the following: commit 88b946ef72928e859d078f3febaf9c76ce0849b9 Merge: bca0277 79ab811 Author: Noah Santacruz Date: Tue Nov 22 09:41:05 2016 +0200 merge commit bca0277424c074af217df5e86abfd2def3a30bc7 Author: Noah Santacruz Date: Tue Nov 22 09:40:03 2016 +0200 removed out.txt commit 79ab811e97fd14bc5899174b198e86f5c6ba2c5f Author: Noah Santacruz Date: Mon Nov 21 18:09:42 2016 +0200 Update README.rst commit 507e4d4cec5b5458b2546ebebe5e49d376b88646 Author: Noah Santacruz Date: Mon Nov 21 18:08:39 2016 +0200 updated init commit 7d3aa5ab33d92b0b374ed1bfbf17807836e465bf Author: Noah Santacruz Date: Mon Nov 21 16:05:06 2016 +0200 changed init commit 29b4c54047ff9ab84b4c95e9ff05ebcb12c15f49 Author: Noah Santacruz Date: Mon Nov 21 16:01:17 2016 +0200 added Hebrew --- README.rst | 1 + num2words/__init__.py | 2 + num2words/lang_HE.py | 162 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 165 insertions(+) create mode 100644 num2words/lang_HE.py diff --git a/README.rst b/README.rst index 1aed5bc..8e8894d 100644 --- a/README.rst +++ b/README.rst @@ -54,6 +54,7 @@ Besides the numerical argument, there's two optional arguments. * ``ru`` (Russian) * ``dk`` (Danish) * ``pt_BR`` (Brazilian Portuguese) +* ``he`` (Hebrew) You can supply values like ``fr_FR``, the code will be correctly interpreted. If you supply an unsupported language, ``NotImplementedError`` is raised. diff --git a/num2words/__init__.py b/num2words/__init__.py index 85d3328..6de57a2 100644 --- a/num2words/__init__.py +++ b/num2words/__init__.py @@ -31,6 +31,7 @@ from . import lang_ID from . import lang_NO from . import lang_DK from . import lang_PT_BR +from . import lang_HE CONVERTER_CLASSES = { 'en': lang_EN.Num2Word_EN(), @@ -48,6 +49,7 @@ CONVERTER_CLASSES = { 'no': lang_NO.Num2Word_NO(), 'dk': lang_DK.Num2Word_DK(), 'pt_BR': lang_PT_BR.Num2Word_PT_BR(), + 'he': lang_HE.Num2Word_HE() } def num2words(number, ordinal=False, lang='en'): diff --git a/num2words/lang_HE.py b/num2words/lang_HE.py new file mode 100644 index 0000000..73857dc --- /dev/null +++ b/num2words/lang_HE.py @@ -0,0 +1,162 @@ +# -*- encoding: utf-8 -*- +# Copyright (c) 2003, Taro Ogawa. All Rights Reserved. +# Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. + +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301 USA + + +from __future__ import unicode_literals + +ZERO = (u'אפס',) + +ONES = { + 1: (u'אחד',), + 2: (u'שנים',), + 3: (u'שלש',), + 4: (u'ארבע',), + 5: (u'חמש',), + 6: (u'שש',), + 7: (u'שבע',), + 8: (u'שמנה',), + 9: (u'תשע',), +} + +TENS = { + 0: (u'עשר',), + 1: (u'אחד עשרה',), + 2: (u'שנים עשרה',), + 3: (u'שלש עשרה',), + 4: (u'ארבע עשרה',), + 5: (u'חמש עשרה',), + 6: (u'שש עשרה',), + 7: (u'שבע עשרה',), + 8: (u'שמנה עשרה',), + 9: (u'תשע עשרה',), +} + +TWENTIES = { + 2: (u'עשרים',), + 3: (u'שלשים',), + 4: (u'ארבעים',), + 5: (u'חמישים',), + 6: (u'ששים',), + 7: (u'שבעים',), + 8: (u'שמנים',), + 9: (u'תשעים',), +} + +HUNDRED = { + 1: (u'מאה',), + 2: (u'מאתיים',), + 3: (u'מאות',) +} + +THOUSANDS = { + 1: (u'אלף',), + 2: (u'אלפיים',), +} + +AND = u'ו' + +def splitby3(n): + length = len(n) + if length > 3: + start = length % 3 + if start > 0: + yield int(n[:start]) + for i in range(start, length, 3): + yield int(n[i:i+3]) + else: + yield int(n) + + +def get_digits(n): + return [int(x) for x in reversed(list(('%03d' % n)[-3:]))] + + +def pluralize(n, forms): + # gettext implementation: + # (n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2) + + form = 0 if (n % 10 == 1 and n % 100 != 11) else 1 if n != 0 else 2 + + return forms[form] + + +def int2word(n): + if n > 9999: #doesn't yet work for numbers this big + raise NotImplementedError() + + if n == 0: + return ZERO[0] + + words = [] + + chunks = list(splitby3(str(n))) + i = len(chunks) + for x in chunks: + i -= 1 + n1, n2, n3 = get_digits(x) + + # print str(n3) + str(n2) + str(n1) + + if n3 > 0: + if n3 <= 2: + words.append(HUNDRED[n3][0]) + else: + words.append(ONES[n3][0]) + words.append(HUNDRED[3][0]) + + if n2 > 1: + words.append(TWENTIES[n2][0]) + + if n2 == 1: + words.append(TENS[n1][0]) + elif n1 > 0 and not (i > 0 and x == 1): + words.append(ONES[n1][0]) + + if i > 0: + if i <= 2: + words.append(THOUSANDS[i][0]) + else: + words.append(ONES[i][0]) + words.append(THOUSANDS[1][0]) + + if len(words) > 1: + words[-1] = AND + words[-1] + return ' '.join(words) + + +def n2w(n): + return int2word(int(n)) + + +def to_currency(n, currency='EUR', cents=True, seperator=','): + raise NotImplementedError() + + +class Num2Word_HE(object): + def to_cardinal(self, number): + return n2w(number) + + def to_ordinal(self, number): + raise NotImplementedError() + + +if __name__ == '__main__': + yo = Num2Word_HE() + nums = [1, 11, 21, 24, 99, 100, 101, 200, 211, 345, 1000, 1011] + for num in nums: + print num, yo.to_cardinal(num) + From f7f1ba45834c007c2559b1f45ec8b6143c134b81 Mon Sep 17 00:00:00 2001 From: Virgil Dupras Date: Tue, 22 Nov 2016 10:29:51 -0500 Subject: [PATCH 27/99] Fix python3 syntax in lang_HE --- num2words/lang_HE.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/num2words/lang_HE.py b/num2words/lang_HE.py index 73857dc..15e67c8 100644 --- a/num2words/lang_HE.py +++ b/num2words/lang_HE.py @@ -16,7 +16,7 @@ # MA 02110-1301 USA -from __future__ import unicode_literals +from __future__ import unicode_literals, print_function ZERO = (u'אפס',) @@ -158,5 +158,5 @@ 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) + print(num, yo.to_cardinal(num)) From 08779b28b27c40f072b6b13116b83df227c40519 Mon Sep 17 00:00:00 2001 From: Brett Anthoine Date: Mon, 18 Jul 2016 08:30:45 +0200 Subject: [PATCH 28/99] Add support for italian. --- num2words/__init__.py | 2 + num2words/lang_IT.py | 204 ++++++++++++++++++++++++++++++++++++++++++ tests/test_it.py | 82 +++++++++++++++++ 3 files changed, 288 insertions(+) create mode 100644 num2words/lang_IT.py create mode 100644 tests/test_it.py diff --git a/num2words/__init__.py b/num2words/__init__.py index 6de57a2..7f878d4 100644 --- a/num2words/__init__.py +++ b/num2words/__init__.py @@ -32,6 +32,7 @@ from . import lang_NO from . import lang_DK from . import lang_PT_BR from . import lang_HE +from . import lang_IT CONVERTER_CLASSES = { 'en': lang_EN.Num2Word_EN(), @@ -50,6 +51,7 @@ CONVERTER_CLASSES = { 'dk': lang_DK.Num2Word_DK(), 'pt_BR': lang_PT_BR.Num2Word_PT_BR(), 'he': lang_HE.Num2Word_HE() + 'it': lang_IT.Num2Word_IT(), } def num2words(number, ordinal=False, lang='en'): diff --git a/num2words/lang_IT.py b/num2words/lang_IT.py new file mode 100644 index 0000000..a46a29c --- /dev/null +++ b/num2words/lang_IT.py @@ -0,0 +1,204 @@ +# -*- encoding: utf-8 -*- +# The PHP License, version 3.01 +# Copyright (c) 1999 - 2010 The PHP Group. All rights reserved. +# +# This source file is subject to version 3.01 of the PHP license, +# that is available at http://www.php.net/license/3_01.txt +# If you did not receive a copy of the PHP license and are unable to +# obtain it through the world-wide-web, please send a note to +# license@php.net so we can mail you a copy immediately. +# +# This code is a direct port to Python of the PHP code of the +# Number_Words package that can be found on pear at the URL : +# http://pear.php.net/package/Numbers_Words +# + +from __future__ import unicode_literals +from .lang_EU import Num2Word_EU + +import re +import math + +class Num2Word_IT(object): + def __init__(self): + self._minus = "meno " + + self._exponent = { + 0 : ('',''), + 3 : ('mille','mila'), + 6 : ('milione','miloni'), + 12 : ('miliardo','miliardi'), + 18 : ('trillone','trilloni'), + 24 : ('quadrilione','quadrilioni')} + + self._digits = ['zero', 'uno', 'due', 'tre', 'quattro', 'cinque', 'sei', 'sette', 'otto', 'nove'] + + self._sep = '' + + def _toWords(self, num, power=0): + str_num = str(num) + # The return string; + ret = '' + + # add a the word for the minus sign if necessary + if num < 0: + ret = self._sep + self._minus + + if len(str_num) > 6: + current_power = 6 + # check for highest power + if self._exponent.has_key(power): + # convert the number above the first 6 digits + # with it's corresponding $power. + snum = str_num[0:-6] + if snum != '': + ret = ret + self._toWords(int(snum), power + 6) + + num = int(str_num[-6:]) + if num == 0: + return ret + + elif num == 0 or str_num == '': + return ' ' + self._digits[0] + ' ' + else: + current_power = len(str_num) + + # See if we need "thousands" + thousands = math.floor(num / 1000) + if thousands == 1: + ret = ret + self._sep + 'mille' + self._sep + elif thousands > 1: + ret = ret + self._toWords(int(thousands), 3) + self._sep + + # values for digits, tens and hundreds + h = int(math.floor((num / 100) % 10)) + t = int(math.floor((num / 10) % 10)) + d = int(math.floor(num % 10)) + + # centinaia: duecento, trecento, etc... + if h == 1: + if ((d==0) and (t == 0)):# is it's '100' use 'cien' + ret = ret + self._sep + 'cento' + else: + ret = ret + self._sep + 'cento' + elif h == 2 or h == 3 or h == 4 or h == 6 or h == 8: + ret = ret + self._sep + self._digits[h] + 'cento' + elif h == 5: + ret = ret + self._sep + 'cinquecento' + elif h == 7: + ret = ret + self._sep + 'settecento' + elif h == 9: + ret = ret + self._sep + 'novecento' + + # decine: venti trenta, etc... + if t == 9: + if d == 1 or d == 8: + ret = ret + self._sep + 'novant' + else: + ret = ret + self._sep + 'novanta' + if t == 8: + if d == 1 or d == 8: + ret = ret + self._sep + 'ottant' + else: + ret = ret + self._sep + 'ottanta' + if t == 7: + if d == 1 or d == 8: + ret = ret + self._sep + 'settant' + else: + ret = ret + self._sep + 'settanta' + if t == 6: + if d == 1 or d == 8: + ret = ret + self._sep + 'sessant' + else: + ret = ret + self._sep + 'sessanta' + if t == 5: + if d == 1 or d == 8: + ret = ret + self._sep + 'cinquant' + else: + ret = ret + self._sep + 'cinquanta' + if t == 4: + if d == 1 or d == 8: + ret = ret + self._sep + 'quarant' + else: + ret = ret + self._sep + 'quaranta' + if t == 3: + if d == 1 or d == 8: + ret = ret + self._sep + 'trent' + else: + ret = ret + self._sep + 'trenta' + if t == 2: + if d == 0: + ret = ret + self._sep + 'venti' + elif (d == 1 or d == 8): + ret = ret + self._sep + 'vent' + self._digits[d] + else: + ret = ret + self._sep + 'venti' + self._digits[d] + if t == 1: + if d == 0: + ret = ret + self._sep + 'dieci' + elif d == 1: + ret = ret + self._sep + 'undici' + elif d == 2: + ret = ret + self._sep + 'dodici' + elif d == 3: + ret = ret + self._sep + 'tredici' + elif d == 4: + ret = ret + self._sep + 'quattordici' + elif d == 5: + ret = ret + self._sep + 'quindici' + elif d == 6: + ret = ret + self._sep + 'sedici' + elif d == 7: + ret = ret + self._sep + 'diciassette' + elif d == 8: + ret = ret + self._sep + 'diciotto' + elif d == 9: + ret = ret + self._sep + 'diciannove' + + # add digits only if it is a multiple of 10 and not 1x or 2x + if t != 1 and t != 2 and d > 0: + # don't add 'e' for numbers below 10 + if t != 0: + # use 'un' instead of 'uno' when there is a suffix ('mila', 'milloni', etc...) + if (power > 0) and ( d == 1): + ret = ret + self._sep + 'e un' + else: + ret = ret + self._sep + '' + self._digits[d] + else: + if power > 0 and d == 1: + ret = ret + self._sep + 'un ' + else: + ret = ret + self._sep + self._digits[d] + + if power > 0: + if self._exponent.has_key(power): + lev = self._exponent[power] + + if lev is None: + return None + + # if it's only one use the singular suffix + if d == 1 and t == 0 and h == 0: + suffix = lev[0] + else: + suffix = lev[1] + + if num != 0: + ret = ret + self._sep + suffix + + return ret + + + def to_cardinal(self, number): + return self._toWords(number) + + def to_ordinal_num(self, number): + pass + + def to_ordinal(self,value): + raise NotImplementedError() + +n2w = Num2Word_IT() +to_card = n2w.to_cardinal +to_ord = n2w.to_ordinal +to_ordnum = n2w.to_ordinal_num diff --git a/tests/test_it.py b/tests/test_it.py new file mode 100644 index 0000000..07cd3a2 --- /dev/null +++ b/tests/test_it.py @@ -0,0 +1,82 @@ +# -*- encoding: utf-8 -*- +# Copyright (c) 2015, 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 unittest import TestCase + +from num2words import num2words + +class Num2WordsITTest(TestCase): + + def test_number(self): + + test_cases = ( + (1,'uno'), + (2,'due'), + (3,'tre'), + (11,'undici'), + (12,'dodici'), + (16,'sedici'), + (19,'diciannove'), + (20,'venti'), + (21,'ventuno'), + (26,'ventisei'), + (30,'trenta'), + (31,'trentuno'), + (40,'quaranta'), + (43,'quarantatre'), + (50,'cinquanta'), + (55,'cinquantacinque'), + (60,'sessanta'), + (67,'sessantasette'), + (70,'settanta'), + (79,'settantanove'), + (100,'cento'), + (101,'centouno'), + (199,'centonovantanove'), + (203,'duecentotre'), + (287,'duecentoottantasette'), + (300,'trecento'), + (356,'trecentocinquantasei'), + (410,'quattrocentodieci'), + (434,'quattrocentotrentaquattro'), + (578,'cinquecentosettantotto'), + (689,'seicentoottantanove'), + (729,'settecentoventinove'), + (894,'ottocentonovantaquattro'), + (999,'novecentonovantanove'), + (1000,'mille'), + (1001,'milleuno'), + (1097,'millenovantasette'), + (1104,'millecentoquattro'), + (1243,'milleduecentoquarantatre'), + (2385,'duemilatrecentoottantacinque'), + (3766,'tremilasettecentosessantasei'), + (4196,'quattromilacentonovantasei'), + (5846,'cinquemilaottocentoquarantasei'), + (6459,'seimilaquattrocentocinquantanove'), + (7232,'settemiladuecentotrentadue'), + (8569,'ottomilacinquecentosessantanove'), + (9539,'novemilacinquecentotrentanove'), + (1000000,'un milione'), + (1000001,'un milioneuno'), + # (1000000100,'un miliardocento'), # DOES NOT WORK TODO: FIX + ) + + for test in test_cases: + self.assertEqual(num2words(test[0], lang='it'), test[1]) + From c9ecd07cbfffaa740e5c471fd5dacc9efde9dd3e Mon Sep 17 00:00:00 2001 From: Brett Anthoine Date: Mon, 18 Jul 2016 11:27:51 +0200 Subject: [PATCH 29/99] Add italian ordinals. --- num2words/lang_IT.py | 15 ++++++++++++++- tests/test_it.py | 14 ++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/num2words/lang_IT.py b/num2words/lang_IT.py index a46a29c..00dfebf 100644 --- a/num2words/lang_IT.py +++ b/num2words/lang_IT.py @@ -196,9 +196,22 @@ class Num2Word_IT(object): pass def to_ordinal(self,value): - raise NotImplementedError() + if 0 <= value <= 10: + return ["primo", "secondo", "terzo", "quarto", "quinto", "sesto", "settimo", "ottavo", "nono", "decimo"][value - 1] + else: + as_word = self._toWords(value) + if as_word.endswith("dici"): + return re.sub("dici$", "dicesimo", as_word) + elif as_word.endswith("to"): + return re.sub("to$", "tesimo", as_word) + elif as_word.endswith("ta"): + return re.sub("ta$", "tesimo", as_word) + else: + return as_word + "simo" + n2w = Num2Word_IT() to_card = n2w.to_cardinal to_ord = n2w.to_ordinal to_ordnum = n2w.to_ordinal_num + diff --git a/tests/test_it.py b/tests/test_it.py index 07cd3a2..57bf646 100644 --- a/tests/test_it.py +++ b/tests/test_it.py @@ -35,6 +35,7 @@ class Num2WordsITTest(TestCase): (20,'venti'), (21,'ventuno'), (26,'ventisei'), + (28,'ventotto'), (30,'trenta'), (31,'trentuno'), (40,'quaranta'), @@ -80,3 +81,16 @@ class Num2WordsITTest(TestCase): for test in test_cases: self.assertEqual(num2words(test[0], lang='it'), test[1]) + def test_ordinal(self): + + test_cases = ( + (1,'primo'), + (8,'ottavo'), + (12,'dodicesimo'), + (14,'quattordicesimo'), + (28,'ventottesimo'), + (100,'centesimo'), + ) + + for test in test_cases: + self.assertEqual(num2words(test[0], lang='it', ordinal=True), test[1]) From bd1f4faf1d1a1e80bc8843874754c2da8c3d7688 Mon Sep 17 00:00:00 2001 From: Brett Anthoine Date: Tue, 10 Jan 2017 14:39:09 +0100 Subject: [PATCH 30/99] Update license header --- num2words/lang_IT.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/num2words/lang_IT.py b/num2words/lang_IT.py index 00dfebf..000068c 100644 --- a/num2words/lang_IT.py +++ b/num2words/lang_IT.py @@ -1,17 +1,17 @@ # -*- encoding: utf-8 -*- -# The PHP License, version 3.01 -# Copyright (c) 1999 - 2010 The PHP Group. All rights reserved. -# -# This source file is subject to version 3.01 of the PHP license, -# that is available at http://www.php.net/license/3_01.txt -# If you did not receive a copy of the PHP license and are unable to -# obtain it through the world-wide-web, please send a note to -# license@php.net so we can mail you a copy immediately. -# -# This code is a direct port to Python of the PHP code of the -# Number_Words package that can be found on pear at the URL : -# http://pear.php.net/package/Numbers_Words # +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301 USA from __future__ import unicode_literals from .lang_EU import Num2Word_EU From 08e915436632fbe8a9193bbcfdef5c481c6007b1 Mon Sep 17 00:00:00 2001 From: Virgil Dupras Date: Wed, 18 Jan 2017 11:15:03 -0500 Subject: [PATCH 31/99] Add travis config --- .travis.yml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..6df6b36 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,9 @@ +sudo: false +language: python +python: + - "2.7" + - "3.4" + - "3.5" + - "3.6" +install: pip install tox-travis +script: tox From 58a4e8e18b704cc06902aae8631c9e60d37580f9 Mon Sep 17 00:00:00 2001 From: Brett Anthoine Date: Wed, 1 Feb 2017 08:49:34 +0100 Subject: [PATCH 32/99] Fix syntax error --- num2words/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/num2words/__init__.py b/num2words/__init__.py index 7f878d4..57c4d57 100644 --- a/num2words/__init__.py +++ b/num2words/__init__.py @@ -50,8 +50,8 @@ CONVERTER_CLASSES = { 'no': lang_NO.Num2Word_NO(), 'dk': lang_DK.Num2Word_DK(), 'pt_BR': lang_PT_BR.Num2Word_PT_BR(), - 'he': lang_HE.Num2Word_HE() - 'it': lang_IT.Num2Word_IT(), + 'he': lang_HE.Num2Word_HE(), + 'it': lang_IT.Num2Word_IT() } def num2words(number, ordinal=False, lang='en'): From 0b80fd42855bf0cb278d8dd858b61cffbba8df97 Mon Sep 17 00:00:00 2001 From: Brett Anthoine Date: Wed, 1 Feb 2017 16:13:24 +0100 Subject: [PATCH 33/99] Use in operator instead of has_key for python3 support --- num2words/lang_IT.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/num2words/lang_IT.py b/num2words/lang_IT.py index 000068c..227883b 100644 --- a/num2words/lang_IT.py +++ b/num2words/lang_IT.py @@ -47,7 +47,7 @@ class Num2Word_IT(object): if len(str_num) > 6: current_power = 6 # check for highest power - if self._exponent.has_key(power): + if power in self._exponent: # convert the number above the first 6 digits # with it's corresponding $power. snum = str_num[0:-6] @@ -171,7 +171,7 @@ class Num2Word_IT(object): ret = ret + self._sep + self._digits[d] if power > 0: - if self._exponent.has_key(power): + if power in self._exponent: lev = self._exponent[power] if lev is None: From 0f21d8f82531c6375888038c4a10807e6687f83d Mon Sep 17 00:00:00 2001 From: Virgil Dupras Date: Wed, 1 Feb 2017 10:31:41 -0500 Subject: [PATCH 34/99] README: Add Italian to the list of supported languages --- README.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/README.rst b/README.rst index 8e8894d..930aae0 100644 --- a/README.rst +++ b/README.rst @@ -55,6 +55,7 @@ Besides the numerical argument, there's two optional arguments. * ``dk`` (Danish) * ``pt_BR`` (Brazilian Portuguese) * ``he`` (Hebrew) +* ``it`` (Italian) You can supply values like ``fr_FR``, the code will be correctly interpreted. If you supply an unsupported language, ``NotImplementedError`` is raised. From 8468654d86089f7c4403de51f8b10f59df02ba39 Mon Sep 17 00:00:00 2001 From: Virgil Dupras Date: Wed, 1 Feb 2017 10:32:10 -0500 Subject: [PATCH 35/99] tox.ini: add py35 and py36 envs --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 13bca3c..0e59285 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py27,py34 +envlist = py27,py34,py35,py36 [testenv] commands = python -m unittest discover From fb281568b2f0a0e2dfef95448cade2012b4c6972 Mon Sep 17 00:00:00 2001 From: Ernesto Rodriguez Ortiz Date: Wed, 1 Feb 2017 14:59:43 -0500 Subject: [PATCH 36/99] Show the TravisCI build status in the project page. --- README.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.rst b/README.rst index 930aae0..beb2da6 100644 --- a/README.rst +++ b/README.rst @@ -1,6 +1,8 @@ num2words - Convert numbers to words in multiple languages ========================================================== +.. image:: https://travis-ci.org/savoirfairelinux/num2words.svg?branch=master :target: https://travis-ci.org/savoirfairelinux/num2words + ``num2words`` is a library that converts numbers like ``42`` to words like ``forty-two``. It supports multiple languages (English, French, Spanish, German and Lithuanian) and can even generate ordinal numbers like ``forty-second`` (altough this last feature is a bit buggy at the moment). From f67d64196889492801a9a37140ec9036fa484d12 Mon Sep 17 00:00:00 2001 From: Krzysztof Socha Date: Sat, 25 Feb 2017 22:44:27 +0100 Subject: [PATCH 37/99] Fixed issues with wrong text for currency conversion with whole 10s (e.g., 123.50) --- num2words/lang_PL.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/num2words/lang_PL.py b/num2words/lang_PL.py index 24078d8..369e41f 100644 --- a/num2words/lang_PL.py +++ b/num2words/lang_PL.py @@ -55,6 +55,9 @@ 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 @@ -95,6 +98,9 @@ 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 @@ -207,7 +213,7 @@ def int2word(n): if n3 > 0: words.append(HUNDREDS[n3][0]) - + if n2 > 1: words.append(TWENTIES[n2][0]) @@ -245,6 +251,8 @@ def to_currency(n, currency='EUR', cents=True, seperator=','): n = str(n).replace(',', '.') if '.' in n: left, right = n.split('.') + if len(right)==1: + right = right+'0' else: left, right = n, 0 left, right = int(left), int(right) From d586f620c59152d9ab1c1d26ee992362f32d4c09 Mon Sep 17 00:00:00 2001 From: Krzysztof Socha Date: Mon, 27 Feb 2017 17:18:06 +0100 Subject: [PATCH 38/99] Added unit tests for Polish language --- @test_95559_tmp | 2 ++ @test_95599_tmp | 2 ++ tests/test_pl.py | 49 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 @test_95559_tmp create mode 100644 @test_95599_tmp create mode 100644 tests/test_pl.py diff --git a/@test_95559_tmp b/@test_95559_tmp new file mode 100644 index 0000000..88d54c1 --- /dev/null +++ b/@test_95559_tmp @@ -0,0 +1,2 @@ +z = z+1 +z = z*2 diff --git a/@test_95599_tmp b/@test_95599_tmp new file mode 100644 index 0000000..88d54c1 --- /dev/null +++ b/@test_95599_tmp @@ -0,0 +1,2 @@ +z = z+1 +z = z*2 diff --git a/tests/test_pl.py b/tests/test_pl.py new file mode 100644 index 0000000..b70b9a6 --- /dev/null +++ b/tests/test_pl.py @@ -0,0 +1,49 @@ +# -*- encoding: utf-8 -*- +# Copyright (c) 2015, 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 unittest import TestCase + +from num2words import num2words +from num2words.lang_PL import to_currency + +class Num2WordsPLTest(TestCase): + def test_cardinal(self): + self.assertEqual(num2words(100, lang='pl'), "sto") + self.assertEqual(num2words(101, lang='pl'), "sto jeden") + self.assertEqual(num2words(110, lang='pl'), "sto dziesięć") + self.assertEqual(num2words(115, lang='pl'), "sto piętnaście") + self.assertEqual(num2words(123, lang='pl'), "sto dwadzieścia trzy") + self.assertEqual(num2words(1000, lang='pl'), "tysiąc") + self.assertEqual(num2words(1001, lang='pl'), "tysiąc jeden") + self.assertEqual(num2words(2012, lang='pl'), "dwa tysiące dwanaście") + self.assertEqual(num2words(12519.85, lang='pl'), "dwanaście tysięcy pięćset dziewiętnaście przecinek osiemdziesiąt pięć") + self.assertEqual(num2words(123.50, lang='pl'), "sto dwadzieścia trzy przecinek pięć") + self.assertEqual(num2words(1234567890, lang='pl'), "miliard dwieście trzydzieści cztery miliony pięćset sześćdziesiąt siedem tysięcy osiemset dziewięćdzisiąt") + self.assertEqual(num2words(215461407892039002157189883901676, lang='pl'), "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ść") + self.assertEqual(num2words(719094234693663034822824384220291, lang='pl'), "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") + + 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'), "tysiąc dwieście trzydzieści cztery euro, pięćdziesiąt sześć centów") + self.assertEqual(to_currency(1234.56, 'PLN'), "tysiąc dwieście trzydzieści cztery złote, pięćdziesiąt sześć groszy") + self.assertEqual(to_currency(10111, 'EUR', seperator=' i'), "sto jeden euro i jedenaście centów") + self.assertEqual(to_currency(10121, 'PLN', seperator=' i'), "sto jeden złotych i dwadzieścia jeden groszy") + self.assertEqual(to_currency(-1251985, 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'), "sto dwadzieścia trzy złote i pięćdziesiąt groszy") + self.assertEqual(to_currency(1950, cents = False), "dziewiętnaście euro, 50 centów") From 94d4e8599246660fe5fde56e501a825db179120a Mon Sep 17 00:00:00 2001 From: Krzysztof Socha Date: Mon, 27 Feb 2017 17:22:31 +0100 Subject: [PATCH 39/99] Cleaned-up some test files --- .DS_Store | Bin 0 -> 6148 bytes @test_95559_tmp | 2 -- @test_95599_tmp | 2 -- 3 files changed, 4 deletions(-) create mode 100644 .DS_Store delete mode 100644 @test_95559_tmp delete mode 100644 @test_95599_tmp diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 Date: Mon, 27 Feb 2017 17:23:52 +0100 Subject: [PATCH 40/99] Cleaned-up some test files --- .DS_Store | Bin 6148 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 5008ddfcf53c02e82d7eee2e57c38e5672ef89f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 Date: Mon, 27 Feb 2017 21:44:43 +0100 Subject: [PATCH 41/99] Fixed integer division operator (/->//) to work also in python3 --- num2words/lang_PL.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/num2words/lang_PL.py b/num2words/lang_PL.py index 369e41f..4ce7380 100644 --- a/num2words/lang_PL.py +++ b/num2words/lang_PL.py @@ -245,7 +245,7 @@ def to_currency(n, currency='EUR', cents=True, seperator=','): minus = False n = abs(n) - left = n / 100 + left = n // 100 right = n % 100 else: n = str(n).replace(',', '.') From 7fdb61351b740111bfe3596b3f4a1aee4f5da925 Mon Sep 17 00:00:00 2001 From: Krzysztof Socha Date: Mon, 27 Feb 2017 21:57:11 +0100 Subject: [PATCH 42/99] Cleaned-up whitespaces around operators --- num2words/lang_PL.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/num2words/lang_PL.py b/num2words/lang_PL.py index 4ce7380..c232f8a 100644 --- a/num2words/lang_PL.py +++ b/num2words/lang_PL.py @@ -184,7 +184,7 @@ def splitby3(n): if start > 0: yield int(n[:start]) for i in range(start, length, 3): - yield int(n[i:i+3]) + yield int(n[i:i + 3]) else: yield int(n) @@ -194,7 +194,7 @@ def get_digits(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 + 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 return forms[form] @@ -209,8 +209,6 @@ def int2word(n): i -= 1 n1, n2, n3 = get_digits(x) - # print str(n3) + str(n2) + str(n1) - if n3 > 0: words.append(HUNDREDS[n3][0]) @@ -237,7 +235,7 @@ def n2w(n): return int2word(int(n)) -def to_currency(n, currency='EUR', cents=True, seperator=','): +def to_currency(n, currency = 'EUR', cents = True, seperator = ','): if type(n) == int: if n < 0: minus = True @@ -251,8 +249,8 @@ def to_currency(n, currency='EUR', cents=True, seperator=','): n = str(n).replace(',', '.') if '.' in n: left, right = n.split('.') - if len(right)==1: - right = right+'0' + if len(right) == 1: + right = right + '0' else: left, right = n, 0 left, right = int(left), int(right) From 907ebbc812f71dd1c5751651b7d08d176d505274 Mon Sep 17 00:00:00 2001 From: Ernesto Rodriguez Ortiz Date: Mon, 27 Feb 2017 16:05:21 -0500 Subject: [PATCH 43/99] Update README.rst to show TravisCI build status. --- README.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index beb2da6..a3808e7 100644 --- a/README.rst +++ b/README.rst @@ -1,7 +1,8 @@ num2words - Convert numbers to words in multiple languages ========================================================== -.. image:: https://travis-ci.org/savoirfairelinux/num2words.svg?branch=master :target: https://travis-ci.org/savoirfairelinux/num2words +.. image:: https://travis-ci.org/savoirfairelinux/num2words.svg?branch=master + :target: https://travis-ci.org/savoirfairelinux/num2words ``num2words`` is a library that converts numbers like ``42`` to words like ``forty-two``. It supports multiple languages (English, French, Spanish, German and Lithuanian) and can even generate From 905faa20fcb8aba57d1aac6eed987653acf8b9af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Moreno?= Date: Thu, 16 Mar 2017 16:31:43 -0500 Subject: [PATCH 44/99] [IMP]Adds new files for ES_CO and ES_VE. --- num2words/lang_ES_CO.py | 183 ++++++++++++++++++++++++++++++++++++++++ num2words/lang_ES_VE.py | 183 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 366 insertions(+) create mode 100644 num2words/lang_ES_CO.py create mode 100644 num2words/lang_ES_VE.py diff --git a/num2words/lang_ES_CO.py b/num2words/lang_ES_CO.py new file mode 100644 index 0000000..9302c7d --- /dev/null +++ b/num2words/lang_ES_CO.py @@ -0,0 +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, print_function +from .lang_EU import Num2Word_EU + + +class Num2Word_ES(Num2Word_EU): + # //CHECK: Is this sufficient?? + def set_high_numwords(self, high): + max = 3 + 6*len(high) + + for word, n in zip(high, range(max, 3, -6)): + self.cards[10**(n-3)] = word + "illón" + + def setup(self): + lows = ["cuatr", "tr", "b", "m"] + self.high_numwords = self.gen_high_numwords([], [], lows) + self.negword = "menos " + self.pointword = "punto" + self.errmsg_nonnum = "Solo números pueden ser convertidos a letras." + self.errmsg_toobig = "Numero muy grande para ser convertido a letras." + self.gender_stem = "o" + self.exclude_title = ["y", "menos", "punto"] + self.mid_numwords = [(1000, "mil"), (100, "cien"), + (90, "noventa"), (80, "ochenta"), + (70, "setenta"), (60, "sesenta"), + (50, "cincuenta"), (40, "cuarenta"), + (30, "treinta")] + self.low_numwords = ["veintinueve", "veintiocho", "veintisiete", + "veintiséis", "veinticinco", "veinticuatro", + "veintitrés", "veintidós", "veintiuno", + "veinte", "diecinueve", "dieciocho", "diecisiete", + "dieciseis", "quince", "catorce", "trece", "doce", + "once", "diez", "nueve", "ocho", "siete", "seis", + "cinco", "cuatro", "tres", "dos", "uno", "cero"] + self.ords = { + 1: "primer", + 2: "segund", + 3: "tercer", + 4: "cuart", + 5: "quint", + 6: "sext", + 7: "séptim", + 8: "octav", + 9: "noven", + 10: "décim", + 20: "vigésim", + 30: "trigésim", + 40: "quadragésim", + 50: "quincuagésim", + 60: "sexagésim", + 70: "septuagésim", + 80: "octogésim", + 90: "nonagésim", + 100: "centésim", + 200: "ducentésim", + 300: "tricentésim", + 400: "cuadrigentésim", + 500: "quingentésim", + 600: "sexcentésim", + 700: "septigentésim", + 800: "octigentésim", + 900: "noningentésim", + 1e3: "milésim", + 1e6: "millonésim", + 1e9: "billonésim", + 1e12: "trillonésim", + 1e15: "cuadrillonésim" + } + + def merge(self, curr, next): + ctext, cnum, ntext, nnum = curr + next + + if cnum == 1: + if nnum < 1000000: + return next + ctext = "un" + elif cnum == 100 and not nnum == 1000: + ctext += "t" + self.gender_stem + + if nnum < cnum: + if cnum < 100: + return ("%s y %s" % (ctext, ntext), cnum + nnum) + return ("%s %s" % (ctext, ntext), cnum + nnum) + elif (not nnum % 1000000) and cnum > 1: + ntext = ntext[:-3] + "lones" + + if nnum == 100: + if cnum == 5: + ctext = "quinien" + ntext = "" + elif cnum == 7: + ctext = "sete" + elif cnum == 9: + ctext = "nove" + ntext += "t" + self.gender_stem + "s" + else: + ntext = " " + ntext + + return (ctext + ntext, cnum * nnum) + + def to_ordinal(self, value): + self.verify_ordinal(value) + text = "" + try: + if value == 0: + text = "" + elif value <= 10: + text = "%s%s" % (self.ords[value], self.gender_stem) + elif value <= 12: + text = "%s%s%s" % (self.ords[10], self.gender_stem, self.to_ordinal(value - 10)) + elif value <= 100: + dec = (value / 10) * 10 + text = "%s%s %s" % (self.ords[dec], self.gender_stem, self.to_ordinal(value - dec)) + elif value <= 1e3: + cen = (value / 100) * 100 + text = "%s%s %s" % (self.ords[cen], self.gender_stem, self.to_ordinal(value - cen)) + elif value < 1e18: + # dec contains the following: + # [ 1e3, 1e6): 1e3 + # [ 1e6, 1e9): 1e6 + # [ 1e9, 1e12): 1e9 + # [1e12, 1e15): 1e12 + # [1e15, 1e18): 1e15 + dec = 10 ** ((((len(str(int(value))) - 1) / 3 - 1) + 1) * 3) + part = int(float(value / dec) * dec) + cardinal = self.to_cardinal(part / dec) if part / dec != 1 else "" + text = "%s%s%s %s" % (cardinal, self.ords[dec], self.gender_stem, self.to_ordinal(value - part)) + else: + text = self.to_cardinal(value) + except KeyError: + text = self.to_cardinal(value) + return text.strip() + + def to_ordinal_num(self, value): + self.verify_ordinal(value) + return "%s%s" % (value, "º" if self.gender_stem == 'o' else "ª") + + def to_currency(self, val, longval=True, old=False): + if old: + return self.to_splitnum(val, hightxt="peso/s", lowtxt="peso/s", + divisor=1000, jointxt="y", longval=longval) + return super(Num2Word_ES, self).to_currency(val, jointxt="y", + longval=longval) + + +n2w = Num2Word_ES() +to_card = n2w.to_cardinal +to_ord = n2w.to_ordinal +to_ordnum = n2w.to_ordinal_num + + +def main(): + for val in [1, 11, 12, 21, 31, 33, 71, 80, 81, 91, 99, 100, 101, 102, 155, + 180, 300, 308, 832, 1000, 1001, 1061, 1100, 1500, 1701, 3000, + 8280, 8291, 150000, 500000, 1000000, 2000000, 2000001, + -21212121211221211111, -2.121212, -1.0000100]: + n2w.test(val) + + n2w.test(1325325436067876801768700107601001012212132143210473207540327057320957032975032975093275093275093270957329057320975093272950730) + print(n2w.to_currency(1222)) + print(n2w.to_currency(1222, old=True)) + print(n2w.to_year(1222)) + + +if __name__ == "__main__": + main() diff --git a/num2words/lang_ES_VE.py b/num2words/lang_ES_VE.py new file mode 100644 index 0000000..d174d07 --- /dev/null +++ b/num2words/lang_ES_VE.py @@ -0,0 +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, print_function +from .lang_EU import Num2Word_EU + + +class Num2Word_ES(Num2Word_EU): + # //CHECK: Is this sufficient?? + def set_high_numwords(self, high): + max = 3 + 6*len(high) + + for word, n in zip(high, range(max, 3, -6)): + self.cards[10**(n-3)] = word + "illón" + + def setup(self): + lows = ["cuatr", "tr", "b", "m"] + self.high_numwords = self.gen_high_numwords([], [], lows) + self.negword = "menos " + self.pointword = "punto" + self.errmsg_nonnum = "Solo números pueden ser convertidos a letras." + self.errmsg_toobig = "Numero muy grande para ser convertido a letras." + self.gender_stem = "o" + self.exclude_title = ["y", "menos", "punto"] + self.mid_numwords = [(1000, "mil"), (100, "cien"), + (90, "noventa"), (80, "ochenta"), + (70, "setenta"), (60, "sesenta"), + (50, "cincuenta"), (40, "cuarenta"), + (30, "treinta")] + self.low_numwords = ["veintinueve", "veintiocho", "veintisiete", + "veintiséis", "veinticinco", "veinticuatro", + "veintitrés", "veintidós", "veintiuno", + "veinte", "diecinueve", "dieciocho", "diecisiete", + "dieciseis", "quince", "catorce", "trece", "doce", + "once", "diez", "nueve", "ocho", "siete", "seis", + "cinco", "cuatro", "tres", "dos", "uno", "cero"] + self.ords = { + 1: "primer", + 2: "segund", + 3: "tercer", + 4: "cuart", + 5: "quint", + 6: "sext", + 7: "séptim", + 8: "octav", + 9: "noven", + 10: "décim", + 20: "vigésim", + 30: "trigésim", + 40: "quadragésim", + 50: "quincuagésim", + 60: "sexagésim", + 70: "septuagésim", + 80: "octogésim", + 90: "nonagésim", + 100: "centésim", + 200: "ducentésim", + 300: "tricentésim", + 400: "cuadrigentésim", + 500: "quingentésim", + 600: "sexcentésim", + 700: "septigentésim", + 800: "octigentésim", + 900: "noningentésim", + 1e3: "milésim", + 1e6: "millonésim", + 1e9: "billonésim", + 1e12: "trillonésim", + 1e15: "cuadrillonésim" + } + + def merge(self, curr, next): + ctext, cnum, ntext, nnum = curr + next + + if cnum == 1: + if nnum < 1000000: + return next + ctext = "un" + elif cnum == 100 and not nnum == 1000: + ctext += "t" + self.gender_stem + + if nnum < cnum: + if cnum < 100: + return ("%s y %s" % (ctext, ntext), cnum + nnum) + return ("%s %s" % (ctext, ntext), cnum + nnum) + elif (not nnum % 1000000) and cnum > 1: + ntext = ntext[:-3] + "lones" + + if nnum == 100: + if cnum == 5: + ctext = "quinien" + ntext = "" + elif cnum == 7: + ctext = "sete" + elif cnum == 9: + ctext = "nove" + ntext += "t" + self.gender_stem + "s" + else: + ntext = " " + ntext + + return (ctext + ntext, cnum * nnum) + + def to_ordinal(self, value): + self.verify_ordinal(value) + text = "" + try: + if value == 0: + text = "" + elif value <= 10: + text = "%s%s" % (self.ords[value], self.gender_stem) + elif value <= 12: + text = "%s%s%s" % (self.ords[10], self.gender_stem, self.to_ordinal(value - 10)) + elif value <= 100: + dec = (value / 10) * 10 + text = "%s%s %s" % (self.ords[dec], self.gender_stem, self.to_ordinal(value - dec)) + elif value <= 1e3: + cen = (value / 100) * 100 + text = "%s%s %s" % (self.ords[cen], self.gender_stem, self.to_ordinal(value - cen)) + elif value < 1e18: + # dec contains the following: + # [ 1e3, 1e6): 1e3 + # [ 1e6, 1e9): 1e6 + # [ 1e9, 1e12): 1e9 + # [1e12, 1e15): 1e12 + # [1e15, 1e18): 1e15 + dec = 10 ** ((((len(str(int(value))) - 1) / 3 - 1) + 1) * 3) + part = int(float(value / dec) * dec) + cardinal = self.to_cardinal(part / dec) if part / dec != 1 else "" + text = "%s%s%s %s" % (cardinal, self.ords[dec], self.gender_stem, self.to_ordinal(value - part)) + else: + text = self.to_cardinal(value) + except KeyError: + text = self.to_cardinal(value) + return text.strip() + + def to_ordinal_num(self, value): + self.verify_ordinal(value) + return "%s%s" % (value, "º" if self.gender_stem == 'o' else "ª") + + def to_currency(self, val, longval=True, old=False): + if old: + return self.to_splitnum(val, hightxt="bolívar/es Fuerte/s", lowtxt="bolívar/es fuerte/s", + divisor=1000, jointxt="y", longval=longval) + return super(Num2Word_ES, self).to_currency(val, jointxt="y", + longval=longval) + + +n2w = Num2Word_ES() +to_card = n2w.to_cardinal +to_ord = n2w.to_ordinal +to_ordnum = n2w.to_ordinal_num + + +def main(): + for val in [1, 11, 12, 21, 31, 33, 71, 80, 81, 91, 99, 100, 101, 102, 155, + 180, 300, 308, 832, 1000, 1001, 1061, 1100, 1500, 1701, 3000, + 8280, 8291, 150000, 500000, 1000000, 2000000, 2000001, + -21212121211221211111, -2.121212, -1.0000100]: + n2w.test(val) + + n2w.test(1325325436067876801768700107601001012212132143210473207540327057320957032975032975093275093275093270957329057320975093272950730) + print(n2w.to_currency(1222)) + print(n2w.to_currency(1222, old=True)) + print(n2w.to_year(1222)) + + +if __name__ == "__main__": + main() From b0bca269244d5e5e17a9a8fede49e881bc0db8d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Moreno?= Date: Thu, 16 Mar 2017 16:33:33 -0500 Subject: [PATCH 45/99] [IMP]Adds new files for ES_CO and ES_VE. --- num2words/lang_ES_CO.py | 2 +- num2words/lang_ES_VE.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/num2words/lang_ES_CO.py b/num2words/lang_ES_CO.py index 9302c7d..b719e05 100644 --- a/num2words/lang_ES_CO.py +++ b/num2words/lang_ES_CO.py @@ -20,7 +20,7 @@ from __future__ import unicode_literals, print_function from .lang_EU import Num2Word_EU -class Num2Word_ES(Num2Word_EU): +class Num2Word_ES_CO(Num2Word_EU): # //CHECK: Is this sufficient?? def set_high_numwords(self, high): max = 3 + 6*len(high) diff --git a/num2words/lang_ES_VE.py b/num2words/lang_ES_VE.py index d174d07..1e7e3b0 100644 --- a/num2words/lang_ES_VE.py +++ b/num2words/lang_ES_VE.py @@ -20,7 +20,7 @@ from __future__ import unicode_literals, print_function from .lang_EU import Num2Word_EU -class Num2Word_ES(Num2Word_EU): +class Num2Word_ES_VE(Num2Word_EU): # //CHECK: Is this sufficient?? def set_high_numwords(self, high): max = 3 + 6*len(high) From 90e7c9dc7d03a5c14c009d79b5b2caa4568d0620 Mon Sep 17 00:00:00 2001 From: Filippo Costa Date: Fri, 17 Mar 2017 14:12:44 +0100 Subject: [PATCH 46/99] Improvements, corrections, and bug fixes for the `lang_IT` module. (#59) * General refactoring and bug fixes for lang_IT * Added Python3 support for lang_IT * Bug fixes for ordinal numerals in lang_IT * Fixed lang_IT for negative values and added tests * Fixes and minor adjustments for floats in lang_IT * Decimal => float in tests for lang_IT * Moved a comment * 'tre's accentuated, big numbers support, ordinal bug fix, comments, tests * 'meno' and 'virgola' and now class values * Destroyed EU inheritance --- num2words/lang_IT.py | 367 +++++++++++++++++++++---------------------- tests/test_it.py | 177 +++++++++++++-------- 2 files changed, 284 insertions(+), 260 deletions(-) diff --git a/num2words/lang_IT.py b/num2words/lang_IT.py index 227883b..8e3cae4 100644 --- a/num2words/lang_IT.py +++ b/num2words/lang_IT.py @@ -16,202 +16,187 @@ from __future__ import unicode_literals from .lang_EU import Num2Word_EU -import re -import math +# Globals +# ------- + +ZERO = "zero" + +CARDINAL_WORDS = [ + ZERO, "uno", "due", "tre", "quattro", "cinque", "sei", "sette", "otto", + "nove", "dieci", "undici", "dodici", "tredici", "quattordici", "quindici", + "sedici", "diciassette", "diciotto", "diciannove" +] + +ORDINAL_WORDS = [ + ZERO, "primo", "secondo", "terzo", "quarto", "quinto", "sesto", "settimo", + "ottavo", "nono", "decimo", "undicesimo", "dodicesimo", "tredicesimo", + "quattordicesimo", "quindicesimo", "sedicesimo", "diciassettesimo", + "diciottesimo", "diciannovesimo" +] + +# The script can extrapolate the missing numbers from the base forms. +STR_TENS = {2: "venti", 3: "trenta", 4: "quaranta", 6: "sessanta"} + +# These prefixes are used for extremely big numbers. +EXPONENT_PREFIXES = [ + ZERO, "m", "b", "tr", "quadr", "quint", "sest", "sett", "ott", "nov", "dec" +] + +# Utils +# ===== + +def phonetic_contraction(string): + return (string + .replace("oo", "o") # ex. "centootto" + .replace("ao", "o") # ex. "settantaotto" + .replace("io", "o") # ex. "ventiotto" + .replace("au", "u") # ex. "trentauno" + ) + +def exponent_length_to_string(exponent_length): + # We always assume `exponent` to be a multiple of 3. If it's not true, then + # Num2Word_IT.big_number_to_cardinal did something wrong. + prefix = EXPONENT_PREFIXES[exponent_length // 6] + if exponent_length % 6 == 0: + return prefix + "ilione" + else: + return prefix + "iliardo" + +def accentuate(string): + # This is inefficient: it may do several rewritings when deleting + # half-sentence accents. However, it is the easiest method and speed is + # not crucial (duh), so... + return " ".join( + # Deletes half-sentence accents and accentuates the last "tre" + [w.replace("tré", "tre")[:-3] + "tré" + # We shouldn't accentuate a single "tre": is has to be a composite + # word. ~~~~~~~~~~ + if w[-3:] == "tre" and len(w) > 3 + # Deletes half-sentence accents anyway + # ~~~~~~~~~~~~~~~~~~~~~~ + else w.replace("tré", "tre") + for w in string.split() + ]) + +def omitt_if_zero(number_to_string): + return "" if number_to_string == ZERO else number_to_string + +# Main class +# ========== + +class Num2Word_IT: + + MINUS_PREFIX_WORD = "meno " + FLOAT_INFIX_WORD = " virgola " -class Num2Word_IT(object): def __init__(self): - self._minus = "meno " - - self._exponent = { - 0 : ('',''), - 3 : ('mille','mila'), - 6 : ('milione','miloni'), - 12 : ('miliardo','miliardi'), - 18 : ('trillone','trilloni'), - 24 : ('quadrilione','quadrilioni')} - - self._digits = ['zero', 'uno', 'due', 'tre', 'quattro', 'cinque', 'sei', 'sette', 'otto', 'nove'] - - self._sep = '' - - def _toWords(self, num, power=0): - str_num = str(num) - # The return string; - ret = '' - - # add a the word for the minus sign if necessary - if num < 0: - ret = self._sep + self._minus - - if len(str_num) > 6: - current_power = 6 - # check for highest power - if power in self._exponent: - # convert the number above the first 6 digits - # with it's corresponding $power. - snum = str_num[0:-6] - if snum != '': - ret = ret + self._toWords(int(snum), power + 6) - - num = int(str_num[-6:]) - if num == 0: - return ret - - elif num == 0 or str_num == '': - return ' ' + self._digits[0] + ' ' - else: - current_power = len(str_num) - - # See if we need "thousands" - thousands = math.floor(num / 1000) - if thousands == 1: - ret = ret + self._sep + 'mille' + self._sep - elif thousands > 1: - ret = ret + self._toWords(int(thousands), 3) + self._sep - - # values for digits, tens and hundreds - h = int(math.floor((num / 100) % 10)) - t = int(math.floor((num / 10) % 10)) - d = int(math.floor(num % 10)) - - # centinaia: duecento, trecento, etc... - if h == 1: - if ((d==0) and (t == 0)):# is it's '100' use 'cien' - ret = ret + self._sep + 'cento' - else: - ret = ret + self._sep + 'cento' - elif h == 2 or h == 3 or h == 4 or h == 6 or h == 8: - ret = ret + self._sep + self._digits[h] + 'cento' - elif h == 5: - ret = ret + self._sep + 'cinquecento' - elif h == 7: - ret = ret + self._sep + 'settecento' - elif h == 9: - ret = ret + self._sep + 'novecento' - - # decine: venti trenta, etc... - if t == 9: - if d == 1 or d == 8: - ret = ret + self._sep + 'novant' - else: - ret = ret + self._sep + 'novanta' - if t == 8: - if d == 1 or d == 8: - ret = ret + self._sep + 'ottant' - else: - ret = ret + self._sep + 'ottanta' - if t == 7: - if d == 1 or d == 8: - ret = ret + self._sep + 'settant' - else: - ret = ret + self._sep + 'settanta' - if t == 6: - if d == 1 or d == 8: - ret = ret + self._sep + 'sessant' - else: - ret = ret + self._sep + 'sessanta' - if t == 5: - if d == 1 or d == 8: - ret = ret + self._sep + 'cinquant' - else: - ret = ret + self._sep + 'cinquanta' - if t == 4: - if d == 1 or d == 8: - ret = ret + self._sep + 'quarant' - else: - ret = ret + self._sep + 'quaranta' - if t == 3: - if d == 1 or d == 8: - ret = ret + self._sep + 'trent' - else: - ret = ret + self._sep + 'trenta' - if t == 2: - if d == 0: - ret = ret + self._sep + 'venti' - elif (d == 1 or d == 8): - ret = ret + self._sep + 'vent' + self._digits[d] - else: - ret = ret + self._sep + 'venti' + self._digits[d] - if t == 1: - if d == 0: - ret = ret + self._sep + 'dieci' - elif d == 1: - ret = ret + self._sep + 'undici' - elif d == 2: - ret = ret + self._sep + 'dodici' - elif d == 3: - ret = ret + self._sep + 'tredici' - elif d == 4: - ret = ret + self._sep + 'quattordici' - elif d == 5: - ret = ret + self._sep + 'quindici' - elif d == 6: - ret = ret + self._sep + 'sedici' - elif d == 7: - ret = ret + self._sep + 'diciassette' - elif d == 8: - ret = ret + self._sep + 'diciotto' - elif d == 9: - ret = ret + self._sep + 'diciannove' - - # add digits only if it is a multiple of 10 and not 1x or 2x - if t != 1 and t != 2 and d > 0: - # don't add 'e' for numbers below 10 - if t != 0: - # use 'un' instead of 'uno' when there is a suffix ('mila', 'milloni', etc...) - if (power > 0) and ( d == 1): - ret = ret + self._sep + 'e un' - else: - ret = ret + self._sep + '' + self._digits[d] - else: - if power > 0 and d == 1: - ret = ret + self._sep + 'un ' - else: - ret = ret + self._sep + self._digits[d] - - if power > 0: - if power in self._exponent: - lev = self._exponent[power] - - if lev is None: - return None - - # if it's only one use the singular suffix - if d == 1 and t == 0 and h == 0: - suffix = lev[0] - else: - suffix = lev[1] - - if num != 0: - ret = ret + self._sep + suffix - - return ret - - - def to_cardinal(self, number): - return self._toWords(number) - - def to_ordinal_num(self, number): pass - def to_ordinal(self,value): - if 0 <= value <= 10: - return ["primo", "secondo", "terzo", "quarto", "quinto", "sesto", "settimo", "ottavo", "nono", "decimo"][value - 1] + def float_to_words(self, float_number, ordinal=False): + if ordinal: + prefix = self.to_ordinal(int(float_number)) else: - as_word = self._toWords(value) - if as_word.endswith("dici"): - return re.sub("dici$", "dicesimo", as_word) - elif as_word.endswith("to"): - return re.sub("to$", "tesimo", as_word) - elif as_word.endswith("ta"): - return re.sub("ta$", "tesimo", as_word) + prefix = self.to_cardinal(int(float_number)) + postfix = " ".join( + # Drops the trailing zero and comma ~~~~ + [self.to_cardinal(int(c)) for c in str(float_number % 1)[2:]] + ) + return prefix + Num2Word_IT.FLOAT_INFIX_WORD + postfix + + def tens_to_cardinal(self, number): + tens = number // 10 + units = number % 10 + if tens in STR_TENS: + prefix = STR_TENS[tens] + else: + prefix = CARDINAL_WORDS[tens][:-1] + "anta" + postfix = omitt_if_zero(CARDINAL_WORDS[units]) + return phonetic_contraction(prefix + postfix) + + def hundreds_to_cardinal(self, number): + hundreds = number // 100 + prefix = "cento" + if hundreds != 1: + prefix = CARDINAL_WORDS[hundreds] + prefix + postfix = omitt_if_zero(self.to_cardinal(number % 100)) + return phonetic_contraction(prefix + postfix) + + def thousands_to_cardinal(self, number): + thousands = number // 1000 + if thousands == 1: + prefix = "mille" + else: + prefix = self.to_cardinal(thousands) + "mila" + postfix = omitt_if_zero(self.to_cardinal(number % 1000)) + # "mille" and "mila" don't need any phonetic contractions + return prefix + postfix + + def big_number_to_cardinal(self, number): + digits = [c for c in str(number)] + length = len(digits) + if length >= 66: + raise NotImplementedError("The given number is too large.") + # This is how many digits come before the "illion" term. + # cento miliardi => 3 + # dieci milioni => 2 + # un miliardo => 1 + predigits = length % 3 or 3 + multiplier = digits[:predigits] + exponent = digits[predigits:] + # Default infix string: "milione", "biliardo", "sestilione", ecc. + infix = exponent_length_to_string(len(exponent)) + if multiplier == ["1"]: + prefix = "un " + else: + prefix = self.to_cardinal(int("".join(multiplier))) + # Plural form ~~~~~~~~~~~ + infix = " " + infix[:-1] + "i" + # Read as: Does the value of exponent equal 0? + if set(exponent) != set("0"): + postfix = self.to_cardinal(int("".join(exponent))) + if " e " in postfix: + infix += ", " else: - return as_word + "simo" + infix += " e " + else: + postfix = "" + return prefix + infix + postfix + def to_cardinal(self, number): + if number < 0: + string = Num2Word_IT.MINUS_PREFIX_WORD + self.to_cardinal(-number) + elif number % 1 != 0: + string = self.float_to_words(number) + elif number < 20: + string = CARDINAL_WORDS[number] + elif number < 100: + string = self.tens_to_cardinal(number) + elif number < 1000: + string = self.hundreds_to_cardinal(number) + elif number < 1000000: + string = self.thousands_to_cardinal(number) + else: + string = self.big_number_to_cardinal(number) + return accentuate(string) -n2w = Num2Word_IT() -to_card = n2w.to_cardinal -to_ord = n2w.to_ordinal -to_ordnum = n2w.to_ordinal_num - + def to_ordinal(self, number): + tens = number % 100 + # Italian grammar is poorly defined here ¯\_(ツ)_/¯: + # centodecimo VS centodieciesimo VS centesimo decimo? + is_outside_teens = not 10 < tens < 20 + if number < 0: + return Num2Word_IT.MINUS_PREFIX_WORD + self.to_ordinal(-number) + elif number % 1 != 0: + return self.float_to_words(number, ordinal=True) + elif number < 20: + return ORDINAL_WORDS[number] + elif is_outside_teens and tens % 10 == 3: + # Gets ride of the accent ~~~~~~~~~~ + return self.to_cardinal(number)[:-1] + "eesimo" + elif is_outside_teens and tens % 10 == 6: + return self.to_cardinal(number) + "esimo" + else: + string = self.to_cardinal(number)[:-1] + if string[-3:] == "mil": + string += "l" + return string + "esimo" diff --git a/tests/test_it.py b/tests/test_it.py index 57bf646..be03634 100644 --- a/tests/test_it.py +++ b/tests/test_it.py @@ -15,82 +15,121 @@ # MA 02110-1301 USA from __future__ import unicode_literals - from unittest import TestCase - from num2words import num2words class Num2WordsITTest(TestCase): - def test_number(self): + maxDiff = None - test_cases = ( - (1,'uno'), - (2,'due'), - (3,'tre'), - (11,'undici'), - (12,'dodici'), - (16,'sedici'), - (19,'diciannove'), - (20,'venti'), - (21,'ventuno'), - (26,'ventisei'), - (28,'ventotto'), - (30,'trenta'), - (31,'trentuno'), - (40,'quaranta'), - (43,'quarantatre'), - (50,'cinquanta'), - (55,'cinquantacinque'), - (60,'sessanta'), - (67,'sessantasette'), - (70,'settanta'), - (79,'settantanove'), - (100,'cento'), - (101,'centouno'), - (199,'centonovantanove'), - (203,'duecentotre'), - (287,'duecentoottantasette'), - (300,'trecento'), - (356,'trecentocinquantasei'), - (410,'quattrocentodieci'), - (434,'quattrocentotrentaquattro'), - (578,'cinquecentosettantotto'), - (689,'seicentoottantanove'), - (729,'settecentoventinove'), - (894,'ottocentonovantaquattro'), - (999,'novecentonovantanove'), - (1000,'mille'), - (1001,'milleuno'), - (1097,'millenovantasette'), - (1104,'millecentoquattro'), - (1243,'milleduecentoquarantatre'), - (2385,'duemilatrecentoottantacinque'), - (3766,'tremilasettecentosessantasei'), - (4196,'quattromilacentonovantasei'), - (5846,'cinquemilaottocentoquarantasei'), - (6459,'seimilaquattrocentocinquantanove'), - (7232,'settemiladuecentotrentadue'), - (8569,'ottomilacinquecentosessantanove'), - (9539,'novemilacinquecentotrentanove'), - (1000000,'un milione'), - (1000001,'un milioneuno'), - # (1000000100,'un miliardocento'), # DOES NOT WORK TODO: FIX - ) + def test_negative(self): + number = 648972145 + pos_crd = num2words(+number, lang="it") + neg_crd = num2words(-number, lang="it") + pos_ord = num2words(+number, lang="it", ordinal=True) + neg_ord = num2words(-number, lang="it", ordinal=True) + self.assertEqual("meno " + pos_crd, neg_crd) + self.assertEqual("meno " + pos_ord, neg_ord) - for test in test_cases: - self.assertEqual(num2words(test[0], lang='it'), test[1]) + def test_float_to_cardinal(self): + self.assertTrue("tre virgola uno quattro uno" in num2words(3.1415, lang="it")) + self.assertTrue("meno cinque virgola uno" in num2words(-5.15, lang="it")) + self.assertTrue("meno zero virgola uno" in num2words(-0.15, lang="it")) - def test_ordinal(self): + def test_float_to_ordinal(self): + self.assertTrue("terzo virgola uno quattro uno" in num2words(3.1415, lang="it", ordinal=True)) + self.assertTrue("meno quinto virgola uno" in num2words(-5.15, lang="it", ordinal=True)) + self.assertTrue("meno zero virgola uno" in num2words(-0.15, lang="it", ordinal=True)) - test_cases = ( - (1,'primo'), - (8,'ottavo'), - (12,'dodicesimo'), - (14,'quattordicesimo'), - (28,'ventottesimo'), - (100,'centesimo'), - ) + def test_0(self): + self.assertEqual(num2words(0, lang="it"), "zero") + self.assertEqual(num2words(0, lang="it", ordinal=True), "zero") - for test in test_cases: - self.assertEqual(num2words(test[0], lang='it', ordinal=True), test[1]) + def test_1_to_10(self): + self.assertEqual(num2words(1, lang="it"), "uno") + self.assertEqual(num2words(2, lang="it"), "due") + self.assertEqual(num2words(7, lang="it"), "sette") + self.assertEqual(num2words(10, lang="it"), "dieci") + + def test_11_to_19(self): + self.assertEqual(num2words(11, lang="it"), "undici") + self.assertEqual(num2words(13, lang="it"), "tredici") + self.assertEqual(num2words(15, lang="it"), "quindici") + self.assertEqual(num2words(16, lang="it"), "sedici") + self.assertEqual(num2words(19, lang="it"), "diciannove") + + def test_20_to_99(self): + self.assertEqual(num2words(20, lang="it"), "venti") + self.assertEqual(num2words(23, lang="it"), "ventitré") + self.assertEqual(num2words(28, lang="it"), "ventotto") + self.assertEqual(num2words(31, lang="it"), "trentuno") + self.assertEqual(num2words(40, lang="it"), "quaranta") + self.assertEqual(num2words(66, lang="it"), "sessantasei") + self.assertEqual(num2words(92, lang="it"), "novantadue") + + def test_100_to_999(self): + self.assertEqual(num2words(100, lang="it"), "cento") + self.assertEqual(num2words(111, lang="it"), "centoundici") + self.assertEqual(num2words(150, lang="it"), "centocinquanta") + self.assertEqual(num2words(196, lang="it"), "centonovantasei") + self.assertEqual(num2words(200, lang="it"), "duecento") + self.assertEqual(num2words(210, lang="it"), "duecentodieci") + self.assertEqual(num2words(701, lang="it"), "settecentouno") + + def test_1000_to_9999(self): + self.assertEqual(num2words(1000, lang="it"), "mille") + self.assertEqual(num2words(1001, lang="it"), "milleuno") + self.assertEqual(num2words(1500, lang="it"), "millecinquecento") + self.assertEqual(num2words(7378, lang="it"), "settemilatrecentosettantotto") + self.assertEqual(num2words(2000, lang="it"), "duemila") + self.assertEqual(num2words(2100, lang="it"), "duemilacento") + self.assertEqual(num2words(6870, lang="it"), "seimilaottocentosettanta") + self.assertEqual(num2words(10000, lang="it"), "diecimila") + self.assertEqual(num2words(98765, lang="it"), "novantottomilasettecentosessantacinque") + self.assertEqual(num2words(100000, lang="it"), "centomila") + self.assertEqual(num2words(523456, lang="it"), "cinquecentoventitremilaquattrocentocinquantasei") + + def test_big(self): + self.assertEqual(num2words(1000000, lang="it"), "un milione") + self.assertEqual(num2words(1000007, lang="it"), "un milione e sette") + self.assertEqual(num2words(1200000, lang="it"), "un milione e duecentomila") + self.assertEqual(num2words(3000000, lang="it"), "tre milioni") + self.assertEqual(num2words(3000005, lang="it"), "tre milioni e cinque") + self.assertEqual(num2words(3800000, lang="it"), "tre milioni e ottocentomila") + self.assertEqual(num2words(1000000000, lang="it"), "un miliardo") + self.assertEqual(num2words(1000000017, lang="it"), "un miliardo e diciassette") + self.assertEqual(num2words(2000000000, lang="it"), "due miliardi") + self.assertEqual(num2words(2000001000, lang="it"), "due miliardi e mille") + self.assertEqual(num2words(1234567890, lang="it"), "un miliardo, duecentotrentaquattro milioni e cinquecentosessantasettemilaottocentonovanta") + self.assertEqual(num2words(1000000000000, lang="it"), "un bilione") + self.assertEqual(num2words(123456789012345678901234567890, lang="it"), "centoventitré quadriliardi, quattrocentocinquantasei quadrilioni, settecentottantanove triliardi, dodici trilioni, trecentoquarantacinque biliardi, seicentosettantotto bilioni, novecentouno miliardi, duecentotrentaquattro milioni e cinquecentosessantasettemilaottocentonovanta") + + def test_nth_1_to_99(self): + self.assertEqual(num2words(1, lang="it", ordinal=True), "primo") + self.assertEqual(num2words(8, lang="it", ordinal=True), "ottavo") + self.assertEqual(num2words(23, lang="it", ordinal=True), "ventitreesimo") + self.assertEqual(num2words(47, lang="it", ordinal=True), "quarantasettesimo") + self.assertEqual(num2words(99, lang="it", ordinal=True), "novantanovesimo") + + def test_nth_100_to_999(self): + self.assertEqual(num2words(100, lang="it", ordinal=True), "centesimo") + self.assertEqual(num2words(112, lang="it", ordinal=True), "centododicesimo") + self.assertEqual(num2words(120, lang="it", ordinal=True), "centoventesimo") + self.assertEqual(num2words(316, lang="it", ordinal=True), "trecentosedicesimo") + self.assertEqual(num2words(700, lang="it", ordinal=True), "settecentesimo") + self.assertEqual(num2words(803, lang="it", ordinal=True), "ottocentotreesimo") + self.assertEqual(num2words(923, lang="it", ordinal=True), "novecentoventitreesimo") + + def test_nth_1000_to_999999(self): + self.assertEqual(num2words(1000, lang="it", ordinal=True), "millesimo") + self.assertEqual(num2words(1001, lang="it", ordinal=True), "milleunesimo") + self.assertEqual(num2words(1003, lang="it", ordinal=True), "milletreesimo") + self.assertEqual(num2words(1200, lang="it", ordinal=True), "milleduecentesimo") + self.assertEqual(num2words(8640, lang="it", ordinal=True), "ottomilaseicentoquarantesimo") + self.assertEqual(num2words(14000, lang="it", ordinal=True), "quattordicimillesimo") + self.assertEqual(num2words(123456, lang="it", ordinal=True), "centoventitremilaquattrocentocinquantaseiesimo") + self.assertEqual(num2words(987654, lang="it", ordinal=True), "novecentottantasettemilaseicentocinquantaquattresimo") + + def test_nth_big(self): + self.assertEqual(num2words(1000000001, lang="it", ordinal=True), "un miliardo e unesimo") + self.assertEqual(num2words(123456789012345678901234567890, lang="it", ordinal=True), "centoventitré quadriliardi, quattrocentocinquantasei quadrilioni, settecentottantanove triliardi, dodici trilioni, trecentoquarantacinque biliardi, seicentosettantotto bilioni, novecentouno miliardi, duecentotrentaquattro milioni e cinquecentosessantasettemilaottocentonovantesimo") From c2148d15efda2196a97470de62c8f92567b660ee Mon Sep 17 00:00:00 2001 From: Diep Huu Hoang Date: Sun, 19 Mar 2017 22:41:41 +0700 Subject: [PATCH 47/99] [ADD] support VietNam --- num2words/__init__.py | 4 +- num2words/lang_VN.py | 92 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 num2words/lang_VN.py diff --git a/num2words/__init__.py b/num2words/__init__.py index 57c4d57..dfb91d0 100644 --- a/num2words/__init__.py +++ b/num2words/__init__.py @@ -33,6 +33,7 @@ from . import lang_DK from . import lang_PT_BR from . import lang_HE from . import lang_IT +from . import lang_VN CONVERTER_CLASSES = { 'en': lang_EN.Num2Word_EN(), @@ -51,7 +52,8 @@ CONVERTER_CLASSES = { 'dk': lang_DK.Num2Word_DK(), 'pt_BR': lang_PT_BR.Num2Word_PT_BR(), 'he': lang_HE.Num2Word_HE(), - 'it': lang_IT.Num2Word_IT() + 'it': lang_IT.Num2Word_IT(), + 'vi_VN': lang_VN.Num2Word_VN() } def num2words(number, ordinal=False, lang='en'): diff --git a/num2words/lang_VN.py b/num2words/lang_VN.py new file mode 100644 index 0000000..c8bdb4f --- /dev/null +++ b/num2words/lang_VN.py @@ -0,0 +1,92 @@ +# -*- 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 + + +to_19 = (u'không', u'một', u'hai', u'ba', u'bốn', u'năm', u'sáu', + u'bảy', u'tám', u'chín', u'mười', u'mười một', u'mười hai', + u'mười ba', u'mười bốn', u'mười lăm', u'mười sáu', u'mười bảy', + u'mười tám', u'mười chín') +tens = (u'hai mươi', u'ba mươi', u'bốn mươi', u'năm mươi', + u'sáu mươi', u'bảy mươi', u'tám mươi', u'chín mươi') +denom = ('', + u'nghìn', u'triệu', u'tỷ', u'nghìn tỷ', u'trăm nghìn tỷ', + 'Quintillion', 'Sextillion', 'Septillion', 'Octillion', 'Nonillion', + 'Decillion', 'Undecillion', 'Duodecillion', 'Tredecillion', + 'Quattuordecillion', 'Sexdecillion', 'Septendecillion', + 'Octodecillion', 'Novemdecillion', 'Vigintillion') + + +class Num2Word_VN(object): + + # convert a value < 100 to English. + def _convert_nn(self, val): + if val < 20: + return to_19[val] + for (dcap, dval) in ((k, 20 + (10 * v)) for (v, k) in enumerate(tens)): + if dval + 10 > val: + if val % 10: + a = u'lăm' + if to_19[val % 10] == u'một': + a = u'mốt' + else: + a = to_19[val % 10] + return dcap + ' ' + a + return dcap + + def _convert_nnn(self, val): + word = '' + (mod, rem) = (val % 100, val // 100) + if rem > 0: + word = to_19[rem] + u' trăm' + if mod > 0: + word = word + ' ' + if mod > 0: + word = word + self._convert_nn(mod) + return word + + def vietnam_number(self, val): + if val < 100: + return self._convert_nn(val) + if val < 1000: + return self._convert_nnn(val) + for (didx, dval) in ((v - 1, 1000 ** v) for v in range(len(denom))): + if dval > val: + mod = 1000 ** didx + l = val // mod + r = val - (l * mod) + ret = self._convert_nnn(l) + ' ' + denom[didx] + if r > 0: + ret = ret + ' ' + self.vietnam_number(r) + return ret + + def number_to_text(self, number): + number = '%.2f' % number + the_list = str(number).split('.') + start_word = self.vietnam_number(int(the_list[0])) + final_result = start_word + if len(the_list) > 1 and int(the_list[1]) > 0: + end_word = self.vietnam_number(int(the_list[1])) + final_result = final_result + ' phẩy ' + end_word + return final_result + + def to_cardinal(self, number): + return self.number_to_text(number) + + def to_ordinal(self, number): + return self.to_cardinal(number) From aff876c4a6667eb47ea4edb7d1696269fede3fac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Moreno?= Date: Mon, 27 Mar 2017 10:23:34 -0500 Subject: [PATCH 48/99] [IMP]Reworked the files ES_CO and ES_VE. --- num2words/lang_ES_CO.py | 136 +--------------------------------------- num2words/lang_ES_VE.py | 136 +--------------------------------------- 2 files changed, 6 insertions(+), 266 deletions(-) diff --git a/num2words/lang_ES_CO.py b/num2words/lang_ES_CO.py index b719e05..d72fe40 100644 --- a/num2words/lang_ES_CO.py +++ b/num2words/lang_ES_CO.py @@ -17,140 +17,10 @@ # MA 02110-1301 USA from __future__ import unicode_literals, print_function -from .lang_EU import Num2Word_EU +from .lang_ES import Num2Word_ES -class Num2Word_ES_CO(Num2Word_EU): - # //CHECK: Is this sufficient?? - def set_high_numwords(self, high): - max = 3 + 6*len(high) - - for word, n in zip(high, range(max, 3, -6)): - self.cards[10**(n-3)] = word + "illón" - - def setup(self): - lows = ["cuatr", "tr", "b", "m"] - self.high_numwords = self.gen_high_numwords([], [], lows) - self.negword = "menos " - self.pointword = "punto" - self.errmsg_nonnum = "Solo números pueden ser convertidos a letras." - self.errmsg_toobig = "Numero muy grande para ser convertido a letras." - self.gender_stem = "o" - self.exclude_title = ["y", "menos", "punto"] - self.mid_numwords = [(1000, "mil"), (100, "cien"), - (90, "noventa"), (80, "ochenta"), - (70, "setenta"), (60, "sesenta"), - (50, "cincuenta"), (40, "cuarenta"), - (30, "treinta")] - self.low_numwords = ["veintinueve", "veintiocho", "veintisiete", - "veintiséis", "veinticinco", "veinticuatro", - "veintitrés", "veintidós", "veintiuno", - "veinte", "diecinueve", "dieciocho", "diecisiete", - "dieciseis", "quince", "catorce", "trece", "doce", - "once", "diez", "nueve", "ocho", "siete", "seis", - "cinco", "cuatro", "tres", "dos", "uno", "cero"] - self.ords = { - 1: "primer", - 2: "segund", - 3: "tercer", - 4: "cuart", - 5: "quint", - 6: "sext", - 7: "séptim", - 8: "octav", - 9: "noven", - 10: "décim", - 20: "vigésim", - 30: "trigésim", - 40: "quadragésim", - 50: "quincuagésim", - 60: "sexagésim", - 70: "septuagésim", - 80: "octogésim", - 90: "nonagésim", - 100: "centésim", - 200: "ducentésim", - 300: "tricentésim", - 400: "cuadrigentésim", - 500: "quingentésim", - 600: "sexcentésim", - 700: "septigentésim", - 800: "octigentésim", - 900: "noningentésim", - 1e3: "milésim", - 1e6: "millonésim", - 1e9: "billonésim", - 1e12: "trillonésim", - 1e15: "cuadrillonésim" - } - - def merge(self, curr, next): - ctext, cnum, ntext, nnum = curr + next - - if cnum == 1: - if nnum < 1000000: - return next - ctext = "un" - elif cnum == 100 and not nnum == 1000: - ctext += "t" + self.gender_stem - - if nnum < cnum: - if cnum < 100: - return ("%s y %s" % (ctext, ntext), cnum + nnum) - return ("%s %s" % (ctext, ntext), cnum + nnum) - elif (not nnum % 1000000) and cnum > 1: - ntext = ntext[:-3] + "lones" - - if nnum == 100: - if cnum == 5: - ctext = "quinien" - ntext = "" - elif cnum == 7: - ctext = "sete" - elif cnum == 9: - ctext = "nove" - ntext += "t" + self.gender_stem + "s" - else: - ntext = " " + ntext - - return (ctext + ntext, cnum * nnum) - - def to_ordinal(self, value): - self.verify_ordinal(value) - text = "" - try: - if value == 0: - text = "" - elif value <= 10: - text = "%s%s" % (self.ords[value], self.gender_stem) - elif value <= 12: - text = "%s%s%s" % (self.ords[10], self.gender_stem, self.to_ordinal(value - 10)) - elif value <= 100: - dec = (value / 10) * 10 - text = "%s%s %s" % (self.ords[dec], self.gender_stem, self.to_ordinal(value - dec)) - elif value <= 1e3: - cen = (value / 100) * 100 - text = "%s%s %s" % (self.ords[cen], self.gender_stem, self.to_ordinal(value - cen)) - elif value < 1e18: - # dec contains the following: - # [ 1e3, 1e6): 1e3 - # [ 1e6, 1e9): 1e6 - # [ 1e9, 1e12): 1e9 - # [1e12, 1e15): 1e12 - # [1e15, 1e18): 1e15 - dec = 10 ** ((((len(str(int(value))) - 1) / 3 - 1) + 1) * 3) - part = int(float(value / dec) * dec) - cardinal = self.to_cardinal(part / dec) if part / dec != 1 else "" - text = "%s%s%s %s" % (cardinal, self.ords[dec], self.gender_stem, self.to_ordinal(value - part)) - else: - text = self.to_cardinal(value) - except KeyError: - text = self.to_cardinal(value) - return text.strip() - - def to_ordinal_num(self, value): - self.verify_ordinal(value) - return "%s%s" % (value, "º" if self.gender_stem == 'o' else "ª") +class Num2Word_ES_CO(Num2Word_ES): def to_currency(self, val, longval=True, old=False): if old: @@ -160,7 +30,7 @@ class Num2Word_ES_CO(Num2Word_EU): longval=longval) -n2w = Num2Word_ES() +n2w = Num2Word_ES_CO() to_card = n2w.to_cardinal to_ord = n2w.to_ordinal to_ordnum = n2w.to_ordinal_num diff --git a/num2words/lang_ES_VE.py b/num2words/lang_ES_VE.py index 1e7e3b0..2ad8150 100644 --- a/num2words/lang_ES_VE.py +++ b/num2words/lang_ES_VE.py @@ -17,140 +17,10 @@ # MA 02110-1301 USA from __future__ import unicode_literals, print_function -from .lang_EU import Num2Word_EU +from .lang_ES import Num2Word_ES -class Num2Word_ES_VE(Num2Word_EU): - # //CHECK: Is this sufficient?? - def set_high_numwords(self, high): - max = 3 + 6*len(high) - - for word, n in zip(high, range(max, 3, -6)): - self.cards[10**(n-3)] = word + "illón" - - def setup(self): - lows = ["cuatr", "tr", "b", "m"] - self.high_numwords = self.gen_high_numwords([], [], lows) - self.negword = "menos " - self.pointword = "punto" - self.errmsg_nonnum = "Solo números pueden ser convertidos a letras." - self.errmsg_toobig = "Numero muy grande para ser convertido a letras." - self.gender_stem = "o" - self.exclude_title = ["y", "menos", "punto"] - self.mid_numwords = [(1000, "mil"), (100, "cien"), - (90, "noventa"), (80, "ochenta"), - (70, "setenta"), (60, "sesenta"), - (50, "cincuenta"), (40, "cuarenta"), - (30, "treinta")] - self.low_numwords = ["veintinueve", "veintiocho", "veintisiete", - "veintiséis", "veinticinco", "veinticuatro", - "veintitrés", "veintidós", "veintiuno", - "veinte", "diecinueve", "dieciocho", "diecisiete", - "dieciseis", "quince", "catorce", "trece", "doce", - "once", "diez", "nueve", "ocho", "siete", "seis", - "cinco", "cuatro", "tres", "dos", "uno", "cero"] - self.ords = { - 1: "primer", - 2: "segund", - 3: "tercer", - 4: "cuart", - 5: "quint", - 6: "sext", - 7: "séptim", - 8: "octav", - 9: "noven", - 10: "décim", - 20: "vigésim", - 30: "trigésim", - 40: "quadragésim", - 50: "quincuagésim", - 60: "sexagésim", - 70: "septuagésim", - 80: "octogésim", - 90: "nonagésim", - 100: "centésim", - 200: "ducentésim", - 300: "tricentésim", - 400: "cuadrigentésim", - 500: "quingentésim", - 600: "sexcentésim", - 700: "septigentésim", - 800: "octigentésim", - 900: "noningentésim", - 1e3: "milésim", - 1e6: "millonésim", - 1e9: "billonésim", - 1e12: "trillonésim", - 1e15: "cuadrillonésim" - } - - def merge(self, curr, next): - ctext, cnum, ntext, nnum = curr + next - - if cnum == 1: - if nnum < 1000000: - return next - ctext = "un" - elif cnum == 100 and not nnum == 1000: - ctext += "t" + self.gender_stem - - if nnum < cnum: - if cnum < 100: - return ("%s y %s" % (ctext, ntext), cnum + nnum) - return ("%s %s" % (ctext, ntext), cnum + nnum) - elif (not nnum % 1000000) and cnum > 1: - ntext = ntext[:-3] + "lones" - - if nnum == 100: - if cnum == 5: - ctext = "quinien" - ntext = "" - elif cnum == 7: - ctext = "sete" - elif cnum == 9: - ctext = "nove" - ntext += "t" + self.gender_stem + "s" - else: - ntext = " " + ntext - - return (ctext + ntext, cnum * nnum) - - def to_ordinal(self, value): - self.verify_ordinal(value) - text = "" - try: - if value == 0: - text = "" - elif value <= 10: - text = "%s%s" % (self.ords[value], self.gender_stem) - elif value <= 12: - text = "%s%s%s" % (self.ords[10], self.gender_stem, self.to_ordinal(value - 10)) - elif value <= 100: - dec = (value / 10) * 10 - text = "%s%s %s" % (self.ords[dec], self.gender_stem, self.to_ordinal(value - dec)) - elif value <= 1e3: - cen = (value / 100) * 100 - text = "%s%s %s" % (self.ords[cen], self.gender_stem, self.to_ordinal(value - cen)) - elif value < 1e18: - # dec contains the following: - # [ 1e3, 1e6): 1e3 - # [ 1e6, 1e9): 1e6 - # [ 1e9, 1e12): 1e9 - # [1e12, 1e15): 1e12 - # [1e15, 1e18): 1e15 - dec = 10 ** ((((len(str(int(value))) - 1) / 3 - 1) + 1) * 3) - part = int(float(value / dec) * dec) - cardinal = self.to_cardinal(part / dec) if part / dec != 1 else "" - text = "%s%s%s %s" % (cardinal, self.ords[dec], self.gender_stem, self.to_ordinal(value - part)) - else: - text = self.to_cardinal(value) - except KeyError: - text = self.to_cardinal(value) - return text.strip() - - def to_ordinal_num(self, value): - self.verify_ordinal(value) - return "%s%s" % (value, "º" if self.gender_stem == 'o' else "ª") +class Num2Word_ES_VE(Num2Word_ES): def to_currency(self, val, longval=True, old=False): if old: @@ -160,7 +30,7 @@ class Num2Word_ES_VE(Num2Word_EU): longval=longval) -n2w = Num2Word_ES() +n2w = Num2Word_ES_VE() to_card = n2w.to_cardinal to_ord = n2w.to_ordinal to_ordnum = n2w.to_ordinal_num From 02b73fd444fda15b38528e3f4cf590d23da20954 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Moreno?= Date: Mon, 27 Mar 2017 10:30:13 -0500 Subject: [PATCH 49/99] [IMP]Deleted unnecessary super return. --- num2words/lang_ES_CO.py | 3 --- num2words/lang_ES_VE.py | 4 ---- 2 files changed, 7 deletions(-) diff --git a/num2words/lang_ES_CO.py b/num2words/lang_ES_CO.py index d72fe40..0f306b6 100644 --- a/num2words/lang_ES_CO.py +++ b/num2words/lang_ES_CO.py @@ -23,11 +23,8 @@ from .lang_ES import Num2Word_ES class Num2Word_ES_CO(Num2Word_ES): def to_currency(self, val, longval=True, old=False): - if old: return self.to_splitnum(val, hightxt="peso/s", lowtxt="peso/s", divisor=1000, jointxt="y", longval=longval) - return super(Num2Word_ES, self).to_currency(val, jointxt="y", - longval=longval) n2w = Num2Word_ES_CO() diff --git a/num2words/lang_ES_VE.py b/num2words/lang_ES_VE.py index 2ad8150..974daf3 100644 --- a/num2words/lang_ES_VE.py +++ b/num2words/lang_ES_VE.py @@ -23,12 +23,8 @@ from .lang_ES import Num2Word_ES class Num2Word_ES_VE(Num2Word_ES): def to_currency(self, val, longval=True, old=False): - if old: return self.to_splitnum(val, hightxt="bolívar/es Fuerte/s", lowtxt="bolívar/es fuerte/s", divisor=1000, jointxt="y", longval=longval) - return super(Num2Word_ES, self).to_currency(val, jointxt="y", - longval=longval) - n2w = Num2Word_ES_VE() to_card = n2w.to_cardinal From 321dfd3bca7010c5ec00afc5688a21c35d570485 Mon Sep 17 00:00:00 2001 From: dazre Date: Thu, 30 Mar 2017 15:33:37 +0300 Subject: [PATCH 50/99] remove middle THOUSANDS in case of zero digits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Error: num2words(1000139, lang='ru') -> миллион *тысяч* сто тридцать девять Fix: num2words(1000139, lang='ru') -> миллион сто тридцать девять --- num2words/lang_RU.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/num2words/lang_RU.py b/num2words/lang_RU.py index 922a852..9e0ad5e 100644 --- a/num2words/lang_RU.py +++ b/num2words/lang_RU.py @@ -243,7 +243,7 @@ def int2word(n, feminine=False): ones = ONES_FEMININE if i == 1 or feminine and i == 0 else ONES words.append(ones[n1][0]) - if i > 0: + if i > 0 and x != 0: words.append(pluralize(x, THOUSANDS[i])) return ' '.join(words) From ba8db2589808c1bb6f95596cfd2741c64da2f1ed Mon Sep 17 00:00:00 2001 From: dazre Date: Thu, 30 Mar 2017 15:37:42 +0300 Subject: [PATCH 51/99] add leading Ones MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's more more correctly in Russian: num2words(1135, lang='ru') -> одна тысяча сто тридцать пять num2words(1000139, lang='ru') -> один миллион сто тридцать девять --- num2words/lang_RU.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/num2words/lang_RU.py b/num2words/lang_RU.py index 9e0ad5e..846d8db 100644 --- a/num2words/lang_RU.py +++ b/num2words/lang_RU.py @@ -239,7 +239,7 @@ def int2word(n, feminine=False): 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]) From 91f3dc6854d5a35273ee46c423dd5d781ac84e5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Moreno?= Date: Thu, 30 Mar 2017 14:59:48 -0500 Subject: [PATCH 52/99] [IMP]Adds new languages in init file. --- num2words/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/num2words/__init__.py b/num2words/__init__.py index 57c4d57..3884ebb 100644 --- a/num2words/__init__.py +++ b/num2words/__init__.py @@ -33,6 +33,8 @@ from . import lang_DK from . import lang_PT_BR from . import lang_HE from . import lang_IT +from . import lang_ES_VE +from . import lang_ES_CO CONVERTER_CLASSES = { 'en': lang_EN.Num2Word_EN(), @@ -42,6 +44,8 @@ CONVERTER_CLASSES = { 'fr_CH': lang_FR_CH.Num2Word_FR_CH(), 'de': lang_DE.Num2Word_DE(), 'es': lang_ES.Num2Word_ES(), + 'es_CO': lang_ES_CO.Num2Word_ES_CO, + 'es_VE': lang_ES_VE.Num2Word_ES_VE, 'id': lang_ID.Num2Word_ID(), 'lt': lang_LT.Num2Word_LT(), 'lv': lang_LV.Num2Word_LV(), From 19d0a903ab58a3ebe91954c778e38a186512d77f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Moreno?= Date: Fri, 31 Mar 2017 10:15:53 -0500 Subject: [PATCH 53/99] [IMP] Adds test files for es, es_co and es_ve. --- tests/test_es.py | 30 ++++++++++++++++++++++++++++++ tests/test_es_co.py | 30 ++++++++++++++++++++++++++++++ tests/test_es_ve.py | 30 ++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+) create mode 100644 tests/test_es.py create mode 100644 tests/test_es_co.py create mode 100644 tests/test_es_ve.py diff --git a/tests/test_es.py b/tests/test_es.py new file mode 100644 index 0000000..3de6e1f --- /dev/null +++ b/tests/test_es.py @@ -0,0 +1,30 @@ +# 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 unittest import TestCase + +from num2words import num2words + +class Num2WordsENTest(TestCase): + def test_and_join_199(self): + # ref https://github.com/savoirfairelinux/num2words/issues/8 + self.assertEqual(num2words(199), "ciento noventa y nueve") + + def test_cardinal_for_float_number(self): + # issue 24 + self.assertEqual(num2words(12.50), "doce punto cincuenta") + self.assertEqual(num2words(12.51), "doce punto cincuenta y uno") + self.assertEqual(num2words(12.53), "doce punto cincuenta y tres") + self.assertEqual(num2words(12.59), "doce punto cincuenta y nueve") \ No newline at end of file diff --git a/tests/test_es_co.py b/tests/test_es_co.py new file mode 100644 index 0000000..3de6e1f --- /dev/null +++ b/tests/test_es_co.py @@ -0,0 +1,30 @@ +# 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 unittest import TestCase + +from num2words import num2words + +class Num2WordsENTest(TestCase): + def test_and_join_199(self): + # ref https://github.com/savoirfairelinux/num2words/issues/8 + self.assertEqual(num2words(199), "ciento noventa y nueve") + + def test_cardinal_for_float_number(self): + # issue 24 + self.assertEqual(num2words(12.50), "doce punto cincuenta") + self.assertEqual(num2words(12.51), "doce punto cincuenta y uno") + self.assertEqual(num2words(12.53), "doce punto cincuenta y tres") + self.assertEqual(num2words(12.59), "doce punto cincuenta y nueve") \ No newline at end of file diff --git a/tests/test_es_ve.py b/tests/test_es_ve.py new file mode 100644 index 0000000..3de6e1f --- /dev/null +++ b/tests/test_es_ve.py @@ -0,0 +1,30 @@ +# 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 unittest import TestCase + +from num2words import num2words + +class Num2WordsENTest(TestCase): + def test_and_join_199(self): + # ref https://github.com/savoirfairelinux/num2words/issues/8 + self.assertEqual(num2words(199), "ciento noventa y nueve") + + def test_cardinal_for_float_number(self): + # issue 24 + self.assertEqual(num2words(12.50), "doce punto cincuenta") + self.assertEqual(num2words(12.51), "doce punto cincuenta y uno") + self.assertEqual(num2words(12.53), "doce punto cincuenta y tres") + self.assertEqual(num2words(12.59), "doce punto cincuenta y nueve") \ No newline at end of file From afcaff81000078d0419332bee9d244321ecb21d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Moreno?= Date: Fri, 31 Mar 2017 10:38:39 -0500 Subject: [PATCH 54/99] [IMP] Adds a better test cases. --- tests/test_es.py | 97 +++++++++++++++++++++++++++++++++++++++----- tests/test_es_co.py | 98 ++++++++++++++++++++++++++++++++++++++++----- tests/test_es_ve.py | 98 ++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 263 insertions(+), 30 deletions(-) diff --git a/tests/test_es.py b/tests/test_es.py index 3de6e1f..59e9457 100644 --- a/tests/test_es.py +++ b/tests/test_es.py @@ -12,19 +12,96 @@ # 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 unittest import TestCase from num2words import num2words -class Num2WordsENTest(TestCase): - def test_and_join_199(self): - # ref https://github.com/savoirfairelinux/num2words/issues/8 - self.assertEqual(num2words(199), "ciento noventa y nueve") - def test_cardinal_for_float_number(self): - # issue 24 - self.assertEqual(num2words(12.50), "doce punto cincuenta") - self.assertEqual(num2words(12.51), "doce punto cincuenta y uno") - self.assertEqual(num2words(12.53), "doce punto cincuenta y tres") - self.assertEqual(num2words(12.59), "doce punto cincuenta y nueve") \ No newline at end of file +class Num2WordsESTest(TestCase): + + def test_number(self): + + test_cases = ( + (1,'uno'), + (2,'dos'), + (3,'tres'), + (11,'once'), + (12,'doce'), + (16,'dieciseis'), + (19,'diecinueve'), + (20,'veinte'), + (21,'veintiuno'), + (26,'veintiseis'), + (28,'vientiocho'), + (30,'treinta'), + (31,'treinta y uno'), + (40,'treinta y dos'), + (43,'treinta y tres'), + (50,'cincuenta'), + (55,'cincuenta y cinco'), + (60,'secenta'), + (67,'secenta y siete'), + (70,'setenta'), + (79,'setenta y nueve'), + (100,'cien'), + (101,'ciento uno'), + (199,'ciento noventa y nueve'), + (203,'docientos tres'), + (287,'docientos ochenta y siete'), + (300,'trecientos'), + (356,'trecientos cincuenta y seis'), + (410,'cuatrocientos'), + (434,'cuatrocientos treinta y cuatro'), + (578,'quinientos setenta y ocho'), + (689,'seiciento ochenta y nueve'), + (729,'setencientos veintinueve'), + (894,'ochocientos noventa y cuatro'), + (999,'novecientos noventa y nueve'), + (1000,'mil'), + (1001,'mil uno'), + (1097,'mil noventa y siete'), + (1104,'mil ciento cuatro'), + (1243,'mil docientos cuarenta y tres'), + (2385,'dos mil trecientos ochenta y cinco'), + (3766,'tresmil setencientos sesenta y seis'), + (4196,'cuatromil ciento noventa y seis'), + (5846,'cinco mil ochocientos cuarenta y seis'), + (6459,'seis mil cuatrocientos cincuenta y nueve'), + (7232,'siete mil docientos treinta y dos'), + (8569,'ocho mil quinientos sesenta y nueve'), + (9539,'nueve mil quinientos treinta y nueve'), + (1000000,'un millon'), + (1000001,'un millon uno'), + # (1000000100,'un miliardocento'), # DOES NOT WORK TODO: FIX + ) + + for test in test_cases: + self.assertEqual(num2words(test[0], lang='es'), test[1]) + + def test_ordinal(self): + + test_cases = ( + (1,'primero'), + (8,'octavo'), + (12,'decimo segundo'), + (14,'decimo cuarto'), + (28,'vigesimo octavo'), + (100,'centesimo'), + ) + + for test in test_cases: + self.assertEqual(num2words(test[0], lang='es', ordinal=True), test[1]) + + def test_currency(self): + test_case = ( + (1, 'una peseta'), + (5, 'cinco pesetas'), + (18, 'dieciocho pesetas'), + (100, 'cien pesetas'), + (1000, 'mil pesetas'), + ) + + for test in test_case: + self.assertAlmostEqual(num2words.to_currency(test, lang='es')) diff --git a/tests/test_es_co.py b/tests/test_es_co.py index 3de6e1f..0ebcd68 100644 --- a/tests/test_es_co.py +++ b/tests/test_es_co.py @@ -13,18 +13,96 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA +from __future__ import unicode_literals + from unittest import TestCase from num2words import num2words -class Num2WordsENTest(TestCase): - def test_and_join_199(self): - # ref https://github.com/savoirfairelinux/num2words/issues/8 - self.assertEqual(num2words(199), "ciento noventa y nueve") - def test_cardinal_for_float_number(self): - # issue 24 - self.assertEqual(num2words(12.50), "doce punto cincuenta") - self.assertEqual(num2words(12.51), "doce punto cincuenta y uno") - self.assertEqual(num2words(12.53), "doce punto cincuenta y tres") - self.assertEqual(num2words(12.59), "doce punto cincuenta y nueve") \ No newline at end of file +class Num2WordsESCOTest(TestCase): + + def test_number(self): + + test_cases = ( + (1,'uno'), + (2,'dos'), + (3,'tres'), + (11,'once'), + (12,'doce'), + (16,'dieciseis'), + (19,'diecinueve'), + (20,'veinte'), + (21,'veintiuno'), + (26,'veintiseis'), + (28,'vientiocho'), + (30,'treinta'), + (31,'treinta y uno'), + (40,'treinta y dos'), + (43,'treinta y tres'), + (50,'cincuenta'), + (55,'cincuenta y cinco'), + (60,'secenta'), + (67,'secenta y siete'), + (70,'setenta'), + (79,'setenta y nueve'), + (100,'cien'), + (101,'ciento uno'), + (199,'ciento noventa y nueve'), + (203,'docientos tres'), + (287,'docientos ochenta y siete'), + (300,'trecientos'), + (356,'trecientos cincuenta y seis'), + (410,'cuatrocientos'), + (434,'cuatrocientos treinta y cuatro'), + (578,'quinientos setenta y ocho'), + (689,'seiciento ochenta y nueve'), + (729,'setencientos veintinueve'), + (894,'ochocientos noventa y cuatro'), + (999,'novecientos noventa y nueve'), + (1000,'mil'), + (1001,'mil uno'), + (1097,'mil noventa y siete'), + (1104,'mil ciento cuatro'), + (1243,'mil docientos cuarenta y tres'), + (2385,'dos mil trecientos ochenta y cinco'), + (3766,'tresmil setencientos sesenta y seis'), + (4196,'cuatromil ciento noventa y seis'), + (5846,'cinco mil ochocientos cuarenta y seis'), + (6459,'seis mil cuatrocientos cincuenta y nueve'), + (7232,'siete mil docientos treinta y dos'), + (8569,'ocho mil quinientos sesenta y nueve'), + (9539,'nueve mil quinientos treinta y nueve'), + (1000000,'un millon'), + (1000001,'un millon uno'), + # (1000000100,'un miliardocento'), # DOES NOT WORK TODO: FIX + ) + + for test in test_cases: + self.assertEqual(num2words(test[0], lang='es_CO'), test[1]) + + def test_ordinal(self): + + test_cases = ( + (1,'primero'), + (8,'octavo'), + (12,'decimo segundo'), + (14,'decimo cuarto'), + (28,'vigesimo octavo'), + (100,'centesimo'), + ) + + for test in test_cases: + self.assertEqual(num2words(test[0], lang='es_CO', ordinal=True), test[1]) + + def test_currency(self): + test_case = ( + (1, 'un peso'), + (5, 'cinco pesos'), + (18, 'dieciocho pesos'), + (100, 'cien pesos'), + (1000, 'mil pesos'), + ) + + for test in test_case: + self.assertAlmostEqual(num2words.to_currency(test, lang='es_CO')) diff --git a/tests/test_es_ve.py b/tests/test_es_ve.py index 3de6e1f..b5d8bdd 100644 --- a/tests/test_es_ve.py +++ b/tests/test_es_ve.py @@ -13,18 +13,96 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA +from __future__ import unicode_literals + from unittest import TestCase from num2words import num2words -class Num2WordsENTest(TestCase): - def test_and_join_199(self): - # ref https://github.com/savoirfairelinux/num2words/issues/8 - self.assertEqual(num2words(199), "ciento noventa y nueve") - def test_cardinal_for_float_number(self): - # issue 24 - self.assertEqual(num2words(12.50), "doce punto cincuenta") - self.assertEqual(num2words(12.51), "doce punto cincuenta y uno") - self.assertEqual(num2words(12.53), "doce punto cincuenta y tres") - self.assertEqual(num2words(12.59), "doce punto cincuenta y nueve") \ No newline at end of file +class Num2WordsESVETest(TestCase): + + def test_number(self): + + test_cases = ( + (1,'uno'), + (2,'dos'), + (3,'tres'), + (11,'once'), + (12,'doce'), + (16,'dieciseis'), + (19,'diecinueve'), + (20,'veinte'), + (21,'veintiuno'), + (26,'veintiseis'), + (28,'vientiocho'), + (30,'treinta'), + (31,'treinta y uno'), + (40,'treinta y dos'), + (43,'treinta y tres'), + (50,'cincuenta'), + (55,'cincuenta y cinco'), + (60,'secenta'), + (67,'secenta y siete'), + (70,'setenta'), + (79,'setenta y nueve'), + (100,'cien'), + (101,'ciento uno'), + (199,'ciento noventa y nueve'), + (203,'docientos tres'), + (287,'docientos ochenta y siete'), + (300,'trecientos'), + (356,'trecientos cincuenta y seis'), + (410,'cuatrocientos'), + (434,'cuatrocientos treinta y cuatro'), + (578,'quinientos setenta y ocho'), + (689,'seiciento ochenta y nueve'), + (729,'setencientos veintinueve'), + (894,'ochocientos noventa y cuatro'), + (999,'novecientos noventa y nueve'), + (1000,'mil'), + (1001,'mil uno'), + (1097,'mil noventa y siete'), + (1104,'mil ciento cuatro'), + (1243,'mil docientos cuarenta y tres'), + (2385,'dos mil trecientos ochenta y cinco'), + (3766,'tresmil setencientos sesenta y seis'), + (4196,'cuatromil ciento noventa y seis'), + (5846,'cinco mil ochocientos cuarenta y seis'), + (6459,'seis mil cuatrocientos cincuenta y nueve'), + (7232,'siete mil docientos treinta y dos'), + (8569,'ocho mil quinientos sesenta y nueve'), + (9539,'nueve mil quinientos treinta y nueve'), + (1000000,'un millon'), + (1000001,'un millon uno'), + # (1000000100,'un miliardocento'), # DOES NOT WORK TODO: FIX + ) + + for test in test_cases: + self.assertEqual(num2words(test[0], lang='es_VE'), test[1]) + + def test_ordinal(self): + + test_cases = ( + (1,'primero'), + (8,'octavo'), + (12,'decimo segundo'), + (14,'decimo cuarto'), + (28,'vigesimo octavo'), + (100,'centesimo'), + ) + + for test in test_cases: + self.assertEqual(num2words(test[0], lang='es_VE', ordinal=True), test[1]) + + def test_currency(self): + test_case = ( + (1, 'un bolivar fuerte'), + (5, 'cinco bolivares fuertes'), + (18, 'dieciocho bolivares fuertes'), + (100, 'cien bolivares fuertes'), + (1000, 'mil bolivares fuertes'), + ) + + for test in test_case: + self.assertAlmostEqual(num2words.to_currency(test, lang='es_VE')) From fb2911deeafe30e94f922389906899f29f825e88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Moreno?= Date: Fri, 31 Mar 2017 10:53:55 -0500 Subject: [PATCH 55/99] [FIX]Fixed typo errors and PEP8 errors. [DEL]Deleted test_case currency. --- num2words/lang_ES.py | 9 ++-- tests/test_es.py | 126 ++++++++++++++++++++----------------------- tests/test_es_co.py | 126 ++++++++++++++++++++----------------------- tests/test_es_ve.py | 125 ++++++++++++++++++++---------------------- 4 files changed, 174 insertions(+), 212 deletions(-) diff --git a/num2words/lang_ES.py b/num2words/lang_ES.py index c010d52..e28e896 100644 --- a/num2words/lang_ES.py +++ b/num2words/lang_ES.py @@ -1,4 +1,4 @@ -#encoding: UTF-8 +# encoding: UTF-8 # Copyright (c) 2003, Taro Ogawa. All Rights Reserved. # Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. @@ -19,16 +19,16 @@ from __future__ import unicode_literals, print_function from .lang_EU import Num2Word_EU + class Num2Word_ES(Num2Word_EU): - #//CHECK: Is this sufficient?? + # //CHECK: Is this sufficient?? def set_high_numwords(self, high): max = 3 + 6*len(high) for word, n in zip(high, range(max, 3, -6)): self.cards[10**(n-3)] = word + "illón" - def setup(self): lows = ["cuatr", "tr", "b", "m"] self.high_numwords = self.gen_high_numwords([], [], lows) @@ -81,7 +81,6 @@ class Num2Word_ES(Num2Word_EU): 1e12 : "trillonésim", 1e15 : "cuadrillonésim" } - def merge(self, curr, next): ctext, cnum, ntext, nnum = curr + next @@ -113,7 +112,6 @@ class Num2Word_ES(Num2Word_EU): return (ctext + ntext, cnum * nnum) - def to_ordinal(self, value): self.verify_ordinal(value) text = "" @@ -151,7 +149,6 @@ class Num2Word_ES(Num2Word_EU): self.verify_ordinal(value) return "%s%s" % (value, "º" if self.gender_stem == 'o' else "ª") - def to_currency(self, val, longval=True, old=False): if old: return self.to_splitnum(val, hightxt="peso/s", lowtxt="peseta/s", diff --git a/tests/test_es.py b/tests/test_es.py index 59e9457..0a2e59b 100644 --- a/tests/test_es.py +++ b/tests/test_es.py @@ -1,3 +1,4 @@ +# encoding: UTF-8 # Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. # This library is free software; you can redistribute it and/or @@ -24,57 +25,56 @@ class Num2WordsESTest(TestCase): def test_number(self): test_cases = ( - (1,'uno'), - (2,'dos'), - (3,'tres'), - (11,'once'), - (12,'doce'), - (16,'dieciseis'), - (19,'diecinueve'), - (20,'veinte'), - (21,'veintiuno'), - (26,'veintiseis'), - (28,'vientiocho'), - (30,'treinta'), - (31,'treinta y uno'), - (40,'treinta y dos'), - (43,'treinta y tres'), - (50,'cincuenta'), - (55,'cincuenta y cinco'), - (60,'secenta'), - (67,'secenta y siete'), - (70,'setenta'), - (79,'setenta y nueve'), - (100,'cien'), - (101,'ciento uno'), - (199,'ciento noventa y nueve'), - (203,'docientos tres'), - (287,'docientos ochenta y siete'), - (300,'trecientos'), - (356,'trecientos cincuenta y seis'), - (410,'cuatrocientos'), - (434,'cuatrocientos treinta y cuatro'), - (578,'quinientos setenta y ocho'), - (689,'seiciento ochenta y nueve'), - (729,'setencientos veintinueve'), - (894,'ochocientos noventa y cuatro'), - (999,'novecientos noventa y nueve'), - (1000,'mil'), - (1001,'mil uno'), - (1097,'mil noventa y siete'), - (1104,'mil ciento cuatro'), - (1243,'mil docientos cuarenta y tres'), - (2385,'dos mil trecientos ochenta y cinco'), - (3766,'tresmil setencientos sesenta y seis'), - (4196,'cuatromil ciento noventa y seis'), - (5846,'cinco mil ochocientos cuarenta y seis'), - (6459,'seis mil cuatrocientos cincuenta y nueve'), - (7232,'siete mil docientos treinta y dos'), - (8569,'ocho mil quinientos sesenta y nueve'), - (9539,'nueve mil quinientos treinta y nueve'), - (1000000,'un millon'), - (1000001,'un millon uno'), - # (1000000100,'un miliardocento'), # DOES NOT WORK TODO: FIX + (1, 'uno'), + (2, 'dos'), + (3, 'tres'), + (11, 'once'), + (12, 'doce'), + (16, 'dieciseis'), + (19, 'diecinueve'), + (20, 'veinte'), + (21, 'veintiuno'), + (26, 'veintiséis'), + (28, 'vientiocho'), + (30, 'treinta'), + (31, 'treinta y uno'), + (40, 'treinta y dos'), + (43, 'treinta y tres'), + (50, 'cincuenta'), + (55, 'cincuenta y cinco'), + (60, 'secenta'), + (67, 'secenta y siete'), + (70, 'setenta'), + (79, 'setenta y nueve'), + (100, 'cien'), + (101, 'ciento uno'), + (199, 'ciento noventa y nueve'), + (203, 'docientos tres'), + (287, 'docientos ochenta y siete'), + (300, 'trecientos'), + (356, 'trecientos cincuenta y seis'), + (410, 'cuatrocientos'), + (434, 'cuatrocientos treinta y cuatro'), + (578, 'quinientos setenta y ocho'), + (689, 'seiciento ochenta y nueve'), + (729, 'setencientos veintinueve'), + (894, 'ochocientos noventa y cuatro'), + (999, 'novecientos noventa y nueve'), + (1000, 'mil'), + (1001, 'mil uno'), + (1097, 'mil noventa y siete'), + (1104, 'mil ciento cuatro'), + (1243, 'mil docientos cuarenta y tres'), + (2385, 'dos mil trecientos ochenta y cinco'), + (3766, 'tresmil setencientos sesenta y seis'), + (4196, 'cuatromil ciento noventa y seis'), + (5846, 'cinco mil ochocientos cuarenta y seis'), + (6459, 'seis mil cuatrocientos cincuenta y nueve'), + (7232, 'siete mil docientos treinta y dos'), + (8569, 'ocho mil quinientos sesenta y nueve'), + (9539, 'nueve mil quinientos treinta y nueve'), + (1000000, 'un millón'), + (1000001, 'un millón uno'), ) for test in test_cases: @@ -83,25 +83,13 @@ class Num2WordsESTest(TestCase): def test_ordinal(self): test_cases = ( - (1,'primero'), - (8,'octavo'), - (12,'decimo segundo'), - (14,'decimo cuarto'), - (28,'vigesimo octavo'), - (100,'centesimo'), + (1, 'primero'), + (8, 'octavo'), + (12, 'décimosegundo'), + (14, 'décimo cuarto'), + (28, 'vigésimo octavo'), + (100, 'centésimo'), ) for test in test_cases: self.assertEqual(num2words(test[0], lang='es', ordinal=True), test[1]) - - def test_currency(self): - test_case = ( - (1, 'una peseta'), - (5, 'cinco pesetas'), - (18, 'dieciocho pesetas'), - (100, 'cien pesetas'), - (1000, 'mil pesetas'), - ) - - for test in test_case: - self.assertAlmostEqual(num2words.to_currency(test, lang='es')) diff --git a/tests/test_es_co.py b/tests/test_es_co.py index 0ebcd68..85c6349 100644 --- a/tests/test_es_co.py +++ b/tests/test_es_co.py @@ -1,3 +1,4 @@ +# encoding: UTF-8 # Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. # This library is free software; you can redistribute it and/or @@ -25,57 +26,56 @@ class Num2WordsESCOTest(TestCase): def test_number(self): test_cases = ( - (1,'uno'), - (2,'dos'), - (3,'tres'), - (11,'once'), - (12,'doce'), - (16,'dieciseis'), - (19,'diecinueve'), - (20,'veinte'), - (21,'veintiuno'), - (26,'veintiseis'), - (28,'vientiocho'), - (30,'treinta'), - (31,'treinta y uno'), - (40,'treinta y dos'), - (43,'treinta y tres'), - (50,'cincuenta'), - (55,'cincuenta y cinco'), - (60,'secenta'), - (67,'secenta y siete'), - (70,'setenta'), - (79,'setenta y nueve'), - (100,'cien'), - (101,'ciento uno'), - (199,'ciento noventa y nueve'), - (203,'docientos tres'), - (287,'docientos ochenta y siete'), - (300,'trecientos'), - (356,'trecientos cincuenta y seis'), - (410,'cuatrocientos'), - (434,'cuatrocientos treinta y cuatro'), - (578,'quinientos setenta y ocho'), - (689,'seiciento ochenta y nueve'), - (729,'setencientos veintinueve'), - (894,'ochocientos noventa y cuatro'), - (999,'novecientos noventa y nueve'), - (1000,'mil'), - (1001,'mil uno'), - (1097,'mil noventa y siete'), - (1104,'mil ciento cuatro'), - (1243,'mil docientos cuarenta y tres'), - (2385,'dos mil trecientos ochenta y cinco'), - (3766,'tresmil setencientos sesenta y seis'), - (4196,'cuatromil ciento noventa y seis'), - (5846,'cinco mil ochocientos cuarenta y seis'), - (6459,'seis mil cuatrocientos cincuenta y nueve'), - (7232,'siete mil docientos treinta y dos'), - (8569,'ocho mil quinientos sesenta y nueve'), - (9539,'nueve mil quinientos treinta y nueve'), - (1000000,'un millon'), - (1000001,'un millon uno'), - # (1000000100,'un miliardocento'), # DOES NOT WORK TODO: FIX + (1, 'uno'), + (2, 'dos'), + (3, 'tres'), + (11, 'once'), + (12, 'doce'), + (16, 'dieciseis'), + (19, 'diecinueve'), + (20, 'veinte'), + (21, 'veintiuno'), + (26, 'veintiséis'), + (28, 'vientiocho'), + (30, 'treinta'), + (31, 'treinta y uno'), + (40, 'treinta y dos'), + (43, 'treinta y tres'), + (50, 'cincuenta'), + (55, 'cincuenta y cinco'), + (60, 'secenta'), + (67, 'secenta y siete'), + (70, 'setenta'), + (79, 'setenta y nueve'), + (100, 'cien'), + (101, 'ciento uno'), + (199, 'ciento noventa y nueve'), + (203, 'docientos tres'), + (287, 'docientos ochenta y siete'), + (300, 'trecientos'), + (356, 'trecientos cincuenta y seis'), + (410, 'cuatrocientos'), + (434, 'cuatrocientos treinta y cuatro'), + (578, 'quinientos setenta y ocho'), + (689, 'seiciento ochenta y nueve'), + (729, 'setencientos veintinueve'), + (894, 'ochocientos noventa y cuatro'), + (999, 'novecientos noventa y nueve'), + (1000, 'mil'), + (1001, 'mil uno'), + (1097, 'mil noventa y siete'), + (1104, 'mil ciento cuatro'), + (1243, 'mil docientos cuarenta y tres'), + (2385, 'dos mil trecientos ochenta y cinco'), + (3766, 'tresmil setencientos sesenta y seis'), + (4196, 'cuatromil ciento noventa y seis'), + (5846, 'cinco mil ochocientos cuarenta y seis'), + (6459, 'seis mil cuatrocientos cincuenta y nueve'), + (7232, 'siete mil docientos treinta y dos'), + (8569, 'ocho mil quinientos sesenta y nueve'), + (9539, 'nueve mil quinientos treinta y nueve'), + (1000000, 'un millón'), + (1000001, 'un millón uno'), ) for test in test_cases: @@ -84,25 +84,13 @@ class Num2WordsESCOTest(TestCase): def test_ordinal(self): test_cases = ( - (1,'primero'), - (8,'octavo'), - (12,'decimo segundo'), - (14,'decimo cuarto'), - (28,'vigesimo octavo'), - (100,'centesimo'), + (1, 'primero'), + (8, 'octavo'), + (12, 'décimo segundo'), + (14, 'décimo cuarto'), + (28, 'vigésimo octavo'), + (100, 'centésimo'), ) for test in test_cases: self.assertEqual(num2words(test[0], lang='es_CO', ordinal=True), test[1]) - - def test_currency(self): - test_case = ( - (1, 'un peso'), - (5, 'cinco pesos'), - (18, 'dieciocho pesos'), - (100, 'cien pesos'), - (1000, 'mil pesos'), - ) - - for test in test_case: - self.assertAlmostEqual(num2words.to_currency(test, lang='es_CO')) diff --git a/tests/test_es_ve.py b/tests/test_es_ve.py index b5d8bdd..1a4db01 100644 --- a/tests/test_es_ve.py +++ b/tests/test_es_ve.py @@ -1,3 +1,4 @@ +# encoding: UTF-8 # Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. # This library is free software; you can redistribute it and/or @@ -25,57 +26,56 @@ class Num2WordsESVETest(TestCase): def test_number(self): test_cases = ( - (1,'uno'), - (2,'dos'), - (3,'tres'), - (11,'once'), - (12,'doce'), - (16,'dieciseis'), - (19,'diecinueve'), - (20,'veinte'), - (21,'veintiuno'), - (26,'veintiseis'), - (28,'vientiocho'), - (30,'treinta'), - (31,'treinta y uno'), - (40,'treinta y dos'), - (43,'treinta y tres'), - (50,'cincuenta'), - (55,'cincuenta y cinco'), - (60,'secenta'), - (67,'secenta y siete'), - (70,'setenta'), - (79,'setenta y nueve'), - (100,'cien'), - (101,'ciento uno'), - (199,'ciento noventa y nueve'), - (203,'docientos tres'), - (287,'docientos ochenta y siete'), - (300,'trecientos'), - (356,'trecientos cincuenta y seis'), - (410,'cuatrocientos'), - (434,'cuatrocientos treinta y cuatro'), - (578,'quinientos setenta y ocho'), - (689,'seiciento ochenta y nueve'), - (729,'setencientos veintinueve'), - (894,'ochocientos noventa y cuatro'), - (999,'novecientos noventa y nueve'), - (1000,'mil'), - (1001,'mil uno'), - (1097,'mil noventa y siete'), - (1104,'mil ciento cuatro'), - (1243,'mil docientos cuarenta y tres'), - (2385,'dos mil trecientos ochenta y cinco'), - (3766,'tresmil setencientos sesenta y seis'), - (4196,'cuatromil ciento noventa y seis'), - (5846,'cinco mil ochocientos cuarenta y seis'), - (6459,'seis mil cuatrocientos cincuenta y nueve'), - (7232,'siete mil docientos treinta y dos'), - (8569,'ocho mil quinientos sesenta y nueve'), - (9539,'nueve mil quinientos treinta y nueve'), - (1000000,'un millon'), - (1000001,'un millon uno'), - # (1000000100,'un miliardocento'), # DOES NOT WORK TODO: FIX + (1, 'uno'), + (2, 'dos'), + (3, 'tres'), + (11, 'once'), + (12, 'doce'), + (16, 'dieciseis'), + (19, 'diecinueve'), + (20, 'veinte'), + (21, 'veintiuno'), + (26, 'veintiséis'), + (28, 'vientiocho'), + (30, 'treinta'), + (31, 'treinta y uno'), + (40, 'treinta y dos'), + (43, 'treinta y tres'), + (50, 'cincuenta'), + (55, 'cincuenta y cinco'), + (60, 'secenta'), + (67, 'secenta y siete'), + (70, 'setenta'), + (79, 'setenta y nueve'), + (100, 'cien'), + (101, 'ciento uno'), + (199, 'ciento noventa y nueve'), + (203, 'docientos tres'), + (287, 'docientos ochenta y siete'), + (300, 'trecientos'), + (356, 'trecientos cincuenta y seis'), + (410, 'cuatrocientos'), + (434, 'cuatrocientos treinta y cuatro'), + (578, 'quinientos setenta y ocho'), + (689, 'seiciento ochenta y nueve'), + (729, 'setencientos veintinueve'), + (894, 'ochocientos noventa y cuatro'), + (999, 'novecientos noventa y nueve'), + (1000, 'mil'), + (1001, 'mil uno'), + (1097, 'mil noventa y siete'), + (1104, 'mil ciento cuatro'), + (1243, 'mil docientos cuarenta y tres'), + (2385, 'dos mil trecientos ochenta y cinco'), + (3766, 'tresmil setencientos sesenta y seis'), + (4196, 'cuatromil ciento noventa y seis'), + (5846, 'cinco mil ochocientos cuarenta y seis'), + (6459, 'seis mil cuatrocientos cincuenta y nueve'), + (7232, 'siete mil docientos treinta y dos'), + (8569, 'ocho mil quinientos sesenta y nueve'), + (9539, 'nueve mil quinientos treinta y nueve'), + (1000000, 'un millón'), + (1000001, 'un millón uno'), ) for test in test_cases: @@ -84,25 +84,14 @@ class Num2WordsESVETest(TestCase): def test_ordinal(self): test_cases = ( - (1,'primero'), - (8,'octavo'), - (12,'decimo segundo'), - (14,'decimo cuarto'), - (28,'vigesimo octavo'), - (100,'centesimo'), + (1, 'primero'), + (8, 'octavo'), + (12, 'décimo segundo'), + (14, 'décimo cuarto'), + (28, 'vigésimo octavo'), + (100, 'centésimo'), ) for test in test_cases: self.assertEqual(num2words(test[0], lang='es_VE', ordinal=True), test[1]) - def test_currency(self): - test_case = ( - (1, 'un bolivar fuerte'), - (5, 'cinco bolivares fuertes'), - (18, 'dieciocho bolivares fuertes'), - (100, 'cien bolivares fuertes'), - (1000, 'mil bolivares fuertes'), - ) - - for test in test_case: - self.assertAlmostEqual(num2words.to_currency(test, lang='es_VE')) From c200d97bd72a74becf46c36eaa667d6c251beeb0 Mon Sep 17 00:00:00 2001 From: Diep Huu Hoang Date: Sat, 1 Apr 2017 12:30:54 +0700 Subject: [PATCH 56/99] [IMP] Improve convert number method and add unittest for Vietnam lang --- num2words/lang_VN.py | 16 +++++-- tests/test_vn.py | 106 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 tests/test_vn.py diff --git a/num2words/lang_VN.py b/num2words/lang_VN.py index c8bdb4f..51b6d88 100644 --- a/num2words/lang_VN.py +++ b/num2words/lang_VN.py @@ -34,7 +34,6 @@ denom = ('', class Num2Word_VN(object): - # convert a value < 100 to English. def _convert_nn(self, val): if val < 20: return to_19[val] @@ -46,6 +45,8 @@ class Num2Word_VN(object): a = u'mốt' else: a = to_19[val % 10] + if to_19[val % 10] == u'năm': + a = u'lăm' return dcap + ' ' + a return dcap @@ -56,7 +57,13 @@ class Num2Word_VN(object): word = to_19[rem] + u' trăm' if mod > 0: word = word + ' ' - if mod > 0: + if mod > 0 and mod < 10: + if mod == 5: + word = word != '' and word + u'lẻ năm' or word + u'năm' + else: + word = word != '' and word + u'lẻ ' \ + + self._convert_nn(mod) or word + self._convert_nn(mod) + if mod >= 10: word = word + self._convert_nn(mod) return word @@ -70,7 +77,10 @@ class Num2Word_VN(object): mod = 1000 ** didx l = val // mod r = val - (l * mod) - ret = self._convert_nnn(l) + ' ' + denom[didx] + + ret = self._convert_nnn(l) + u' ' + denom[didx] + if r > 0 and r <= 99: + ret = self._convert_nnn(l) + u' ' + denom[didx] + u' lẻ' if r > 0: ret = ret + ' ' + self.vietnam_number(r) return ret diff --git a/tests/test_vn.py b/tests/test_vn.py new file mode 100644 index 0000000..bf357b3 --- /dev/null +++ b/tests/test_vn.py @@ -0,0 +1,106 @@ +# -*- encoding: utf-8 -*- +# Copyright (c) 2015, 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 unittest import TestCase +from num2words import num2words + +class Num2WordsVNTest(TestCase): + + + def test_0(self): + self.assertEqual(num2words(0, lang="vi_VN"), "không") + + def test_1_to_10(self): + self.assertEqual(num2words(1, lang="vi_VN"), "một") + self.assertEqual(num2words(2, lang="vi_VN"), "hai") + self.assertEqual(num2words(7, lang="vi_VN"), "bảy") + self.assertEqual(num2words(10, lang="vi_VN"), "mười") + + def test_11_to_19(self): + self.assertEqual(num2words(11, lang="vi_VN"), "mười một") + self.assertEqual(num2words(13, lang="vi_VN"), "mười ba") + self.assertEqual(num2words(14, lang="vi_VN"), "mười bốn") + self.assertEqual(num2words(15, lang="vi_VN"), "mười lăm") + self.assertEqual(num2words(16, lang="vi_VN"), "mười sáu") + self.assertEqual(num2words(19, lang="vi_VN"), "mười chín") + + def test_20_to_99(self): + self.assertEqual(num2words(20, lang="vi_VN"), "hai mươi") + self.assertEqual(num2words(23, lang="vi_VN"), "hai mươi ba") + self.assertEqual(num2words(28, lang="vi_VN"), "hai mươi tám") + self.assertEqual(num2words(31, lang="vi_VN"), "ba mươi mốt") + self.assertEqual(num2words(40, lang="vi_VN"), "bốn mươi") + self.assertEqual(num2words(66, lang="vi_VN"), "sáu mươi sáu") + self.assertEqual(num2words(92, lang="vi_VN"), "chín mươi hai") + + def test_100_to_999(self): + self.assertEqual(num2words(100, lang="vi_VN"), "một trăm") + self.assertEqual(num2words(150, lang="vi_VN"), "một trăm năm mươi") + self.assertEqual(num2words(196, lang="vi_VN"), "một trăm chín mươi sáu") + self.assertEqual(num2words(200, lang="vi_VN"), "hai trăm") + self.assertEqual(num2words(210, lang="vi_VN"), "hai trăm mười") + + def test_1000_to_9999(self): + self.assertEqual(num2words(1000, lang="vi_VN"), "một nghìn") + self.assertEqual(num2words(1500, lang="vi_VN"), "một nghìn năm trăm") + self.assertEqual(num2words(7378, lang="vi_VN"), "bảy nghìn ba trăm bảy mươi tám") + self.assertEqual(num2words(2000, lang="vi_VN"), "hai nghìn") + self.assertEqual(num2words(2100, lang="vi_VN"), "hai nghìn một trăm") + self.assertEqual(num2words(6870, lang="vi_VN"), "sáu nghìn tám trăm bảy mươi") + self.assertEqual(num2words(10000, lang="vi_VN"), "mười nghìn") + self.assertEqual(num2words(100000, lang="vi_VN"), "một trăm nghìn") + self.assertEqual(num2words(523456, lang="vi_VN"), "năm trăm hai mươi ba nghìn bốn trăm năm mươi sáu") + + def test_big(self): + self.assertEqual(num2words(1000000, lang="vi_VN"), "một triệu") + self.assertEqual(num2words(1200000, lang="vi_VN"), "một triệu hai trăm nghìn") + self.assertEqual(num2words(3000000, lang="vi_VN"), "ba triệu") + self.assertEqual(num2words(3800000, lang="vi_VN"), "ba triệu tám trăm nghìn") + self.assertEqual(num2words(1000000000, lang="vi_VN"), "một tỷ") + self.assertEqual(num2words(2000000000, lang="vi_VN"), "hai tỷ") + self.assertEqual(num2words(2000001000, lang="vi_VN"), "hai tỷ một nghìn") + self.assertEqual(num2words(1234567890, lang="vi_VN"), "một tỷ hai trăm ba mươi bốn triệu năm trăm sáu mươi bảy nghìn tám trăm chín mươi") + + + def test_decimal_number(self): + self.assertEqual(num2words(1000.11, lang="vi_VN"), "một nghìn phẩy mười một") + self.assertEqual(num2words(1000.21, lang="vi_VN"), "một nghìn phẩy hai mươi mốt") + + def test_special_number(self): + """ + Some number will have some specail rule + """ + self.assertEqual(num2words(21, lang="vi_VN"), "hai mươi mốt") + self.assertEqual(num2words(25, lang="vi_VN"), "hai mươi lăm") + # >100 + self.assertEqual(num2words(101, lang="vi_VN"), "một trăm lẻ một") + self.assertEqual(num2words(105, lang="vi_VN"), "một trăm lẻ năm") + self.assertEqual(num2words(701, lang="vi_VN"), "bảy trăm lẻ một") + self.assertEqual(num2words(705, lang="vi_VN"), "bảy trăm lẻ năm") + + # >1000 + self.assertEqual(num2words(1001, lang="vi_VN"), "một nghìn lẻ một") + self.assertEqual(num2words(1005, lang="vi_VN"), "một nghìn lẻ năm") + self.assertEqual(num2words(98765, lang="vi_VN"), "chín mươi tám nghìn bảy trăm sáu mươi lăm") + + # > 1000000 + self.assertEqual(num2words(3000005, lang="vi_VN"), "ba triệu lẻ năm") + self.assertEqual(num2words(1000007, lang="vi_VN"), "một triệu lẻ bảy") + + # > 1000000000 + self.assertEqual(num2words(1000000017, lang="vi_VN"), "một tỷ lẻ mười bảy") + self.assertEqual(num2words(1000101017, lang="vi_VN"), "một tỷ một trăm lẻ một nghìn lẻ mười bảy") From 76fd9d905fc74de358108b4eb15e47102b5b41da Mon Sep 17 00:00:00 2001 From: Ernesto Rodriguez Ortiz Date: Mon, 3 Apr 2017 17:29:03 -0400 Subject: [PATCH 57/99] Fix the tests after the changes proposed by @10537 Ref: issuer # 10537 --- num2words/__init__.py | 4 +- num2words/lang_ES.py | 9 +-- tests/test_es.py | 134 +++++++++++++++++++++--------------------- tests/test_es_co.py | 78 +++--------------------- tests/test_es_ve.py | 79 +++---------------------- 5 files changed, 90 insertions(+), 214 deletions(-) diff --git a/num2words/__init__.py b/num2words/__init__.py index 3884ebb..9aafb84 100644 --- a/num2words/__init__.py +++ b/num2words/__init__.py @@ -44,8 +44,8 @@ CONVERTER_CLASSES = { 'fr_CH': lang_FR_CH.Num2Word_FR_CH(), 'de': lang_DE.Num2Word_DE(), 'es': lang_ES.Num2Word_ES(), - 'es_CO': lang_ES_CO.Num2Word_ES_CO, - 'es_VE': lang_ES_VE.Num2Word_ES_VE, + 'es_CO': lang_ES_CO.Num2Word_ES_CO(), + 'es_VE': lang_ES_VE.Num2Word_ES_VE(), 'id': lang_ID.Num2Word_ID(), 'lt': lang_LT.Num2Word_LT(), 'lv': lang_LV.Num2Word_LV(), diff --git a/num2words/lang_ES.py b/num2words/lang_ES.py index e28e896..c831a1a 100644 --- a/num2words/lang_ES.py +++ b/num2words/lang_ES.py @@ -162,11 +162,12 @@ to_card = n2w.to_cardinal to_ord = n2w.to_ordinal to_ordnum = n2w.to_ordinal_num + def main(): - for val in [ 1, 11, 12, 21, 31, 33, 71, 80, 81, 91, 99, 100, 101, 102, 155, - 180, 300, 308, 832, 1000, 1001, 1061, 1100, 1500, 1701, 3000, - 8280, 8291, 150000, 500000, 1000000, 2000000, 2000001, - -21212121211221211111, -2.121212, -1.0000100]: + for val in [1, 11, 12, 21, 31, 33, 71, 80, 81, 91, 99, 100, 101, 102, 155, + 180, 300, 308, 832, 1000, 1001, 1061, 1100, 1500, 1701, 3000, + 8280, 8291, 150000, 500000, 1000000, 2000000, 2000001, + -21212121211221211111, -2.121212, -1.0000100]: n2w.test(val) n2w.test(1325325436067876801768700107601001012212132143210473207540327057320957032975032975093275093275093270957329057320975093272950730) diff --git a/tests/test_es.py b/tests/test_es.py index 0a2e59b..cbfa6ba 100644 --- a/tests/test_es.py +++ b/tests/test_es.py @@ -19,77 +19,77 @@ from unittest import TestCase from num2words import num2words +TEST_CASES_CARDINAL = ( + (1, 'uno'), + (2, 'dos'), + (3, 'tres'), + (11, 'once'), + (12, 'doce'), + (16, 'dieciseis'), + (19, 'diecinueve'), + (20, 'veinte'), + (21, 'veintiuno'), + (26, 'veintiséis'), + (28, 'veintiocho'), + (30, 'treinta'), + (31, 'treinta y uno'), + (40, 'cuarenta'), + (44, 'cuarenta y cuatro'), + (50, 'cincuenta'), + (55, 'cincuenta y cinco'), + (60, 'sesenta'), + (67, 'sesenta y siete'), + (70, 'setenta'), + (79, 'setenta y nueve'), + (100, 'cien'), + (101, 'ciento uno'), + (199, 'ciento noventa y nueve'), + (203, 'doscientos tres'), + (287, 'doscientos ochenta y siete'), + (300, 'trescientos'), + (356, 'trescientos cincuenta y seis'), + (400, 'cuatrocientos'), + (434, 'cuatrocientos treinta y cuatro'), + (578, 'quinientos setenta y ocho'), + (689, 'seiscientos ochenta y nueve'), + (729, 'setecientos veintinueve'), + (894, 'ochocientos noventa y cuatro'), + (999, 'novecientos noventa y nueve'), + (1000, 'mil'), + (1001, 'mil uno'), + (1097, 'mil noventa y siete'), + (1104, 'mil ciento cuatro'), + (1243, 'mil doscientos cuarenta y tres'), + (2385, 'dos mil trescientos ochenta y cinco'), + (3766, 'tres mil setecientos sesenta y seis'), + (4196, 'cuatro mil ciento noventa y seis'), + (5846, 'cinco mil ochocientos cuarenta y seis'), + (6459, 'seis mil cuatrocientos cincuenta y nueve'), + (7232, 'siete mil doscientos treinta y dos'), + (8569, 'ocho mil quinientos sesenta y nueve'), + (9539, 'nueve mil quinientos treinta y nueve'), + (1000000, 'un millón'), + (1000001, 'un millón uno'), +) + +TEST_CASES_ORDINAL = ( + (1, 'primero'), + (8, 'octavo'), + (12, 'décimosegundo'), + (14, 'décimo cuarto'), + (28, 'vigésimo octavo'), + (100, 'centésimo'), +) class Num2WordsESTest(TestCase): def test_number(self): - - test_cases = ( - (1, 'uno'), - (2, 'dos'), - (3, 'tres'), - (11, 'once'), - (12, 'doce'), - (16, 'dieciseis'), - (19, 'diecinueve'), - (20, 'veinte'), - (21, 'veintiuno'), - (26, 'veintiséis'), - (28, 'vientiocho'), - (30, 'treinta'), - (31, 'treinta y uno'), - (40, 'treinta y dos'), - (43, 'treinta y tres'), - (50, 'cincuenta'), - (55, 'cincuenta y cinco'), - (60, 'secenta'), - (67, 'secenta y siete'), - (70, 'setenta'), - (79, 'setenta y nueve'), - (100, 'cien'), - (101, 'ciento uno'), - (199, 'ciento noventa y nueve'), - (203, 'docientos tres'), - (287, 'docientos ochenta y siete'), - (300, 'trecientos'), - (356, 'trecientos cincuenta y seis'), - (410, 'cuatrocientos'), - (434, 'cuatrocientos treinta y cuatro'), - (578, 'quinientos setenta y ocho'), - (689, 'seiciento ochenta y nueve'), - (729, 'setencientos veintinueve'), - (894, 'ochocientos noventa y cuatro'), - (999, 'novecientos noventa y nueve'), - (1000, 'mil'), - (1001, 'mil uno'), - (1097, 'mil noventa y siete'), - (1104, 'mil ciento cuatro'), - (1243, 'mil docientos cuarenta y tres'), - (2385, 'dos mil trecientos ochenta y cinco'), - (3766, 'tresmil setencientos sesenta y seis'), - (4196, 'cuatromil ciento noventa y seis'), - (5846, 'cinco mil ochocientos cuarenta y seis'), - (6459, 'seis mil cuatrocientos cincuenta y nueve'), - (7232, 'siete mil docientos treinta y dos'), - (8569, 'ocho mil quinientos sesenta y nueve'), - (9539, 'nueve mil quinientos treinta y nueve'), - (1000000, 'un millón'), - (1000001, 'un millón uno'), - ) - - for test in test_cases: + for test in TEST_CASES_CARDINAL: self.assertEqual(num2words(test[0], lang='es'), test[1]) def test_ordinal(self): - - test_cases = ( - (1, 'primero'), - (8, 'octavo'), - (12, 'décimosegundo'), - (14, 'décimo cuarto'), - (28, 'vigésimo octavo'), - (100, 'centésimo'), - ) - - for test in test_cases: - self.assertEqual(num2words(test[0], lang='es', ordinal=True), test[1]) + for test in TEST_CASES_ORDINAL: + self.assertEqual( + num2words(test[0], lang='es', ordinal=True), + test[1] + ) diff --git a/tests/test_es_co.py b/tests/test_es_co.py index 85c6349..8fc8892 100644 --- a/tests/test_es_co.py +++ b/tests/test_es_co.py @@ -16,81 +16,19 @@ from __future__ import unicode_literals -from unittest import TestCase - from num2words import num2words +from . import test_es -class Num2WordsESCOTest(TestCase): +class Num2WordsESCOTest(test_es.Num2WordsESTest): def test_number(self): - - test_cases = ( - (1, 'uno'), - (2, 'dos'), - (3, 'tres'), - (11, 'once'), - (12, 'doce'), - (16, 'dieciseis'), - (19, 'diecinueve'), - (20, 'veinte'), - (21, 'veintiuno'), - (26, 'veintiséis'), - (28, 'vientiocho'), - (30, 'treinta'), - (31, 'treinta y uno'), - (40, 'treinta y dos'), - (43, 'treinta y tres'), - (50, 'cincuenta'), - (55, 'cincuenta y cinco'), - (60, 'secenta'), - (67, 'secenta y siete'), - (70, 'setenta'), - (79, 'setenta y nueve'), - (100, 'cien'), - (101, 'ciento uno'), - (199, 'ciento noventa y nueve'), - (203, 'docientos tres'), - (287, 'docientos ochenta y siete'), - (300, 'trecientos'), - (356, 'trecientos cincuenta y seis'), - (410, 'cuatrocientos'), - (434, 'cuatrocientos treinta y cuatro'), - (578, 'quinientos setenta y ocho'), - (689, 'seiciento ochenta y nueve'), - (729, 'setencientos veintinueve'), - (894, 'ochocientos noventa y cuatro'), - (999, 'novecientos noventa y nueve'), - (1000, 'mil'), - (1001, 'mil uno'), - (1097, 'mil noventa y siete'), - (1104, 'mil ciento cuatro'), - (1243, 'mil docientos cuarenta y tres'), - (2385, 'dos mil trecientos ochenta y cinco'), - (3766, 'tresmil setencientos sesenta y seis'), - (4196, 'cuatromil ciento noventa y seis'), - (5846, 'cinco mil ochocientos cuarenta y seis'), - (6459, 'seis mil cuatrocientos cincuenta y nueve'), - (7232, 'siete mil docientos treinta y dos'), - (8569, 'ocho mil quinientos sesenta y nueve'), - (9539, 'nueve mil quinientos treinta y nueve'), - (1000000, 'un millón'), - (1000001, 'un millón uno'), - ) - - for test in test_cases: + for test in test_es.TEST_CASES_CARDINAL: self.assertEqual(num2words(test[0], lang='es_CO'), test[1]) def test_ordinal(self): - - test_cases = ( - (1, 'primero'), - (8, 'octavo'), - (12, 'décimo segundo'), - (14, 'décimo cuarto'), - (28, 'vigésimo octavo'), - (100, 'centésimo'), - ) - - for test in test_cases: - self.assertEqual(num2words(test[0], lang='es_CO', ordinal=True), test[1]) + for test in test_es.TEST_CASES_ORDINAL: + self.assertEqual( + num2words(test[0], lang='es_CO', ordinal=True), + test[1] + ) diff --git a/tests/test_es_ve.py b/tests/test_es_ve.py index 1a4db01..596ff4d 100644 --- a/tests/test_es_ve.py +++ b/tests/test_es_ve.py @@ -16,82 +16,19 @@ from __future__ import unicode_literals -from unittest import TestCase - from num2words import num2words +from . import test_es -class Num2WordsESVETest(TestCase): +class Num2WordsESVETest(test_es.Num2WordsESTest): def test_number(self): - - test_cases = ( - (1, 'uno'), - (2, 'dos'), - (3, 'tres'), - (11, 'once'), - (12, 'doce'), - (16, 'dieciseis'), - (19, 'diecinueve'), - (20, 'veinte'), - (21, 'veintiuno'), - (26, 'veintiséis'), - (28, 'vientiocho'), - (30, 'treinta'), - (31, 'treinta y uno'), - (40, 'treinta y dos'), - (43, 'treinta y tres'), - (50, 'cincuenta'), - (55, 'cincuenta y cinco'), - (60, 'secenta'), - (67, 'secenta y siete'), - (70, 'setenta'), - (79, 'setenta y nueve'), - (100, 'cien'), - (101, 'ciento uno'), - (199, 'ciento noventa y nueve'), - (203, 'docientos tres'), - (287, 'docientos ochenta y siete'), - (300, 'trecientos'), - (356, 'trecientos cincuenta y seis'), - (410, 'cuatrocientos'), - (434, 'cuatrocientos treinta y cuatro'), - (578, 'quinientos setenta y ocho'), - (689, 'seiciento ochenta y nueve'), - (729, 'setencientos veintinueve'), - (894, 'ochocientos noventa y cuatro'), - (999, 'novecientos noventa y nueve'), - (1000, 'mil'), - (1001, 'mil uno'), - (1097, 'mil noventa y siete'), - (1104, 'mil ciento cuatro'), - (1243, 'mil docientos cuarenta y tres'), - (2385, 'dos mil trecientos ochenta y cinco'), - (3766, 'tresmil setencientos sesenta y seis'), - (4196, 'cuatromil ciento noventa y seis'), - (5846, 'cinco mil ochocientos cuarenta y seis'), - (6459, 'seis mil cuatrocientos cincuenta y nueve'), - (7232, 'siete mil docientos treinta y dos'), - (8569, 'ocho mil quinientos sesenta y nueve'), - (9539, 'nueve mil quinientos treinta y nueve'), - (1000000, 'un millón'), - (1000001, 'un millón uno'), - ) - - for test in test_cases: + for test in test_es.TEST_CASES_CARDINAL: self.assertEqual(num2words(test[0], lang='es_VE'), test[1]) def test_ordinal(self): - - test_cases = ( - (1, 'primero'), - (8, 'octavo'), - (12, 'décimo segundo'), - (14, 'décimo cuarto'), - (28, 'vigésimo octavo'), - (100, 'centésimo'), - ) - - for test in test_cases: - self.assertEqual(num2words(test[0], lang='es_VE', ordinal=True), test[1]) - + for test in test_es.TEST_CASES_ORDINAL: + self.assertEqual( + num2words(test[0], lang='es_VE', ordinal=True), + test[1] + ) From 9028a5e90b196cdf939ea7e1570a334af0930e49 Mon Sep 17 00:00:00 2001 From: Ernesto Rodriguez Ortiz Date: Mon, 3 Apr 2017 17:43:07 -0400 Subject: [PATCH 58/99] Made to_ordinal() implementation python3 compatible for lang es Ref: issue # 10537 --- num2words/lang_ES.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/num2words/lang_ES.py b/num2words/lang_ES.py index c831a1a..79222ff 100644 --- a/num2words/lang_ES.py +++ b/num2words/lang_ES.py @@ -93,8 +93,8 @@ class Num2Word_ES(Num2Word_EU): if nnum < cnum: if cnum < 100: - return ("%s y %s"%(ctext, ntext), cnum + nnum) - return ("%s %s"%(ctext, ntext), cnum + nnum) + return "%s y %s"%(ctext, ntext), cnum + nnum + return "%s %s"%(ctext, ntext), cnum + nnum elif (not nnum % 1000000) and cnum > 1: ntext = ntext[:-3] + "lones" @@ -123,10 +123,10 @@ class Num2Word_ES(Num2Word_EU): elif value <= 12: text = "%s%s%s" % (self.ords[10], self.gender_stem, self.to_ordinal(value - 10)) elif value <= 100: - dec = (value / 10) * 10 + dec = (value // 10) * 10 text = "%s%s %s" % (self.ords[dec], self.gender_stem, self.to_ordinal(value - dec)) elif value <= 1e3: - cen = (value / 100) * 100 + cen = (value // 100) * 100 text = "%s%s %s" % (self.ords[cen], self.gender_stem, self.to_ordinal(value - cen)) elif value < 1e18: # dec contains the following: From e226cf7d736bbd1aa96dbbf27f34730af59a127b Mon Sep 17 00:00:00 2001 From: dazre Date: Tue, 4 Apr 2017 17:32:55 +0300 Subject: [PATCH 59/99] add test --- tests/test_ru.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 tests/test_ru.py diff --git a/tests/test_ru.py b/tests/test_ru.py new file mode 100644 index 0000000..d4f4087 --- /dev/null +++ b/tests/test_ru.py @@ -0,0 +1,33 @@ +# -*- encoding: utf-8 -*- +# 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 unittest import TestCase + +from num2words import num2words + +class Num2WordsRUTest(TestCase): + + def test_cardinal(self): + self.assertEqual(num2words(5, lang='ru'), u"пять") + self.assertEqual(num2words(15, lang='ru'), u"пятнадцать") + self.assertEqual(num2words(154, lang='ru'), u"сто пятьдесят четыре") + self.assertEqual(num2words(1135, lang='ru'), u"одна тысяча сто тридцать пять") + self.assertEqual(num2words(418531, lang='ru'), u"четыреста восемнадцать тысяч пятьсот тридцать один") + self.assertEqual(num2words(1000139, lang='ru'), u"один миллион сто тридцать девять") + + def test_floating_point(self): + self.assertEqual(num2words(5.2, lang='ru'), u"пять запятая два") + self.assertEqual(num2words(561.42, lang='ru'), u"пятьсот шестьдесят один запятая сорок два") From dd1a3f09a360ace1941ab9ff6e9f9d1d7e0f329b Mon Sep 17 00:00:00 2001 From: cclauss Date: Wed, 12 Apr 2017 21:20:37 +0200 Subject: [PATCH 60/99] classifiers=CLASSIFIERS, This will populate the lower left of https://pypi.org/project/num2words --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index ab6aaf2..24b4bd2 100644 --- a/setup.py +++ b/setup.py @@ -29,4 +29,5 @@ setup( url='https://github.com/savoirfairelinux/num2words', packages=find_packages(exclude=['tests']), test_suite='tests', + classifiers=CLASSIFIERS, ) From f423a9398f8cccd60a19b2afc22139e7d58401b4 Mon Sep 17 00:00:00 2001 From: Dhaifallah Alwadani Date: Wed, 21 Jun 2017 22:20:22 +0300 Subject: [PATCH 61/99] add support for Arabic --- num2words/__init__.py | 2 + num2words/lang_AR.py | 121 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 num2words/lang_AR.py diff --git a/num2words/__init__.py b/num2words/__init__.py index ae864e7..69ad8db 100644 --- a/num2words/__init__.py +++ b/num2words/__init__.py @@ -16,6 +16,7 @@ from __future__ import unicode_literals +from . import lang_AR from . import lang_EN from . import lang_EN_GB from . import lang_EN_IN @@ -39,6 +40,7 @@ from . import lang_VN 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(), diff --git a/num2words/lang_AR.py b/num2words/lang_AR.py new file mode 100644 index 0000000..56c5c4e --- /dev/null +++ b/num2words/lang_AR.py @@ -0,0 +1,121 @@ +# Copyright (c) 2003, Taro Ogawa. All Rights Reserved. +# Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. + +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301 USA + +from __future__ import division, unicode_literals, print_function +from . import lang_EU + +class Num2Word_AR(lang_EU.Num2Word_EU): + def set_high_numwords(self, high): + max = 3 + 3*len(high) + for word, n in zip(high, range(max, 3, -3)): + self.cards[10**n] = word + "illion" + + def setup(self): + self.negword = "minus " + self.pointword = "point" + self.errmsg_nornum = "Only numbers may be converted to words." + self.exclude_title = ["and", "point", "minus"] + + self.mid_numwords = [(1000000, "مليون"),(1000, "ألف"), (100, "مئة"), + (90, "تسعين"), (80, "ثمانين"), (70, "سبعين"), + (60, "ستين"), (50, "خمسين"), (40, "أربعين"), + (30, "ثلاثين")] + self.low_numwords = ["عشرين", "تسعة عشر", "ثمانية عشر", "سبعة عشر", + "sixteen", "خمسة عشر", "fourteen", "thirteen", + "twelve", "أحد عشر", "ten", "nine", "ثمانية", + "seven", "six", "خمسة", "أربعة", "three", "اثنين", + "واحد", "صفر"] + self.ords = { "one" : "first", + "two" : "second", + "three" : "third", + "five" : "fifth", + "eight" : "eighth", + "nine" : "ninth", + "twelve" : "twelfth" } + + + def merge(self, lpair, rpair): + ltext, lnum = lpair + rtext, rnum = rpair + if lnum == 1 and rnum < 100: + return (rtext, rnum) + elif 100 > lnum > rnum : + return ("%s و%s"%(rtext, ltext), rnum + lnum) + elif lnum >= 100 > rnum: + return ("%s و %s"%(ltext, rtext), lnum + rnum) + elif rnum > lnum: + if lnum == 1 and rnum in [100, 1000]: + return ("%s"%(rtext), rnum * lnum) + if lnum == 2 and rnum == 100: + return ("مئتين", rnum * lnum) + if lnum == 2 and rnum in [100, 1000]: + return ("%sين"%(rtext), rnum * lnum) + return ("%s %s"%(ltext, rtext), lnum * rnum) + return ("%s، %s"%(ltext, rtext), lnum + rnum) + + + def to_ordinal(self, value): + self.verify_ordinal(value) + outwords = self.to_cardinal(value).split(" ") + lastwords = outwords[-1].split("-") + lastword = lastwords[-1].lower() + try: + lastword = self.ords[lastword] + except KeyError: + if lastword[-1] == "y": + lastword = lastword[:-1] + "ie" + lastword += "th" + lastwords[-1] = self.title(lastword) + outwords[-1] = "،".join(lastwords) + return " ".join(outwords) + + + def to_ordinal_num(self, value): + self.verify_ordinal(value) + return "%s%s"%(value, self.to_ordinal(value)[-2:]) + + + def to_year(self, val, longval=True): + if not (val//100)%10: + return self.to_cardinal(val) + return self.to_splitnum(val, hightxt="hundred", jointxt="and", + longval=longval) + + def to_currency(self, val, longval=True): + return self.to_splitnum(val, hightxt="dollar/s", lowtxt="cent/s", + jointxt="and", longval=longval, cents = True) + + +n2w = Num2Word_AR() +to_card = n2w.to_cardinal +to_ord = n2w.to_ordinal +to_ordnum = n2w.to_ordinal_num +to_year = n2w.to_year + +def main(): + for val in [ 1, 11, 12, 21, 31, 33, 71, 80, 81, 91, 99, 100, 101, 102, 155, + 180, 300, 308, 832, 1000, 1001, 1061, 1100, 1500, 1701, 3000, + 8280, 8291, 150000, 500000, 1000000, 2000000, 2000001, + -21212121211221211111, -2.121212, -1.0000100]: + n2w.test(val) + n2w.test(1325325436067876801768700107601001012212132143210473207540327057320957032975032975093275093275093270957329057320975093272950730) + for val in [1,120,1000,1120,1800, 1976,2000,2010,2099,2171]: + print(val, "is", n2w.to_currency(val)) + print(val, "is", n2w.to_year(val)) + + +if __name__ == "__main__": + main() From 79215605140bcfbc40dad095f844652e914fd48e Mon Sep 17 00:00:00 2001 From: Dhaifallah Alwadani Date: Wed, 21 Jun 2017 22:22:27 +0300 Subject: [PATCH 62/99] Add arabic to README --- README.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/README.rst b/README.rst index a3808e7..606b1ca 100644 --- a/README.rst +++ b/README.rst @@ -45,6 +45,7 @@ Besides the numerical argument, there's two optional arguments. **lang:** The language in which to convert the number. Supported values are: * ``en`` (English, default) +* ``ar`` (Arabic) * ``fr`` (French) * ``de`` (German) * ``es`` (Spanish) From eea901734a7b37d89170c1eddc9cf5c2446f9762 Mon Sep 17 00:00:00 2001 From: Dhaifallah Alwadani Date: Thu, 22 Jun 2017 23:22:33 +0300 Subject: [PATCH 63/99] fix encoding --- num2words/lang_AR.py | 1 + 1 file changed, 1 insertion(+) diff --git a/num2words/lang_AR.py b/num2words/lang_AR.py index 56c5c4e..7c748b0 100644 --- a/num2words/lang_AR.py +++ b/num2words/lang_AR.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # Copyright (c) 2003, Taro Ogawa. All Rights Reserved. # Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. From 6c3e75d4c826c952d198a5350b5e868ce2611d14 Mon Sep 17 00:00:00 2001 From: Dhaifallah Alwadani Date: Thu, 22 Jun 2017 23:48:44 +0300 Subject: [PATCH 64/99] fix missing words --- num2words/lang_AR.py | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/num2words/lang_AR.py b/num2words/lang_AR.py index 7c748b0..aee780b 100644 --- a/num2words/lang_AR.py +++ b/num2words/lang_AR.py @@ -25,27 +25,28 @@ class Num2Word_AR(lang_EU.Num2Word_EU): self.cards[10**n] = word + "illion" def setup(self): - self.negword = "minus " - self.pointword = "point" + self.negword = "سالب " + self.pointword = "فاصلة" self.errmsg_nornum = "Only numbers may be converted to words." - self.exclude_title = ["and", "point", "minus"] + self.exclude_title = ["و", "فاصلة", "سالب"] self.mid_numwords = [(1000000, "مليون"),(1000, "ألف"), (100, "مئة"), (90, "تسعين"), (80, "ثمانين"), (70, "سبعين"), (60, "ستين"), (50, "خمسين"), (40, "أربعين"), (30, "ثلاثين")] self.low_numwords = ["عشرين", "تسعة عشر", "ثمانية عشر", "سبعة عشر", - "sixteen", "خمسة عشر", "fourteen", "thirteen", - "twelve", "أحد عشر", "ten", "nine", "ثمانية", - "seven", "six", "خمسة", "أربعة", "three", "اثنين", + "ستة عشر", "خمسة عشر", "أربعة عشر", "ثلاثة عشر", + "اثناعشر", "أحد عشر", "عشرة", "تسعة", "ثمانية", + "سبعة", "ستة", "خمسة", "أربعة", "ثلاثة", "اثنين", "واحد", "صفر"] - self.ords = { "one" : "first", - "two" : "second", - "three" : "third", - "five" : "fifth", - "eight" : "eighth", - "nine" : "ninth", - "twelve" : "twelfth" } + self.ords = { "واحد" : "أول", + "اثنين" : "ثاني", + "ثلاثة" : "ثالث", + "أربعة": "رابع", + "خمسة" : "خامس", + "ثمانية" : "ثامن", + "تسعة" : "تاسع", + "اثناعشر" : "ثاني عشر" } def merge(self, lpair, rpair): @@ -58,7 +59,7 @@ class Num2Word_AR(lang_EU.Num2Word_EU): elif lnum >= 100 > rnum: return ("%s و %s"%(ltext, rtext), lnum + rnum) elif rnum > lnum: - if lnum == 1 and rnum in [100, 1000]: + if lnum == 1 and rnum in [100, 1000, 1000000]: return ("%s"%(rtext), rnum * lnum) if lnum == 2 and rnum == 100: return ("مئتين", rnum * lnum) @@ -76,9 +77,7 @@ class Num2Word_AR(lang_EU.Num2Word_EU): try: lastword = self.ords[lastword] except KeyError: - if lastword[-1] == "y": - lastword = lastword[:-1] + "ie" - lastword += "th" + lastword += "" lastwords[-1] = self.title(lastword) outwords[-1] = "،".join(lastwords) return " ".join(outwords) From 7f3f65d9f4c794d293242271d099e00c84298555 Mon Sep 17 00:00:00 2001 From: Dhaifallah Alwadani Date: Thu, 22 Jun 2017 23:49:07 +0300 Subject: [PATCH 65/99] Add arabic tests --- tests/test_ar.py | 62 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 tests/test_ar.py diff --git a/tests/test_ar.py b/tests/test_ar.py new file mode 100644 index 0000000..6b0f6e7 --- /dev/null +++ b/tests/test_ar.py @@ -0,0 +1,62 @@ +# encoding: UTF-8 +# 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 unittest import TestCase + +from num2words import num2words + +TEST_CASES_CARDINAL = ( + (1, 'واحد'), + (2, 'اثنين'), + (11, 'أحد عشر'), + (12, 'اثناعشر'), + (20, 'عشرين'), + (21, 'واحد وعشرين'), + (26, 'ستة وعشرين'), + (30, 'ثلاثين'), + (67, 'سبعة وستين'), + (70, 'سبعين'), + (100, 'مئة'), + (101, 'مئة و واحد'), + (199, 'مئة و تسعة وتسعين'), + (203, 'مئتين و ثلاثة'), + (1000, 'ألف'), + (1001, 'ألف و واحد'), + (1097, 'ألف و سبعة وتسعين'), + (1000000, 'مليون'), + (1000001, 'مليون و واحد'), +) + +TEST_CASES_ORDINAL = ( + (1, 'أول'), + (8, 'ثامن'), + (12, 'ثاني عشر'), + (100, 'مئة'), +) + +class Num2WordsARTest(TestCase): + + def test_number(self): + for test in TEST_CASES_CARDINAL: + self.assertEqual(num2words(test[0], lang='ar'), test[1]) + + def test_ordinal(self): + for test in TEST_CASES_ORDINAL: + self.assertEqual( + num2words(test[0], lang='ar', ordinal=True), + test[1] + ) From 21db1b32c3778e314a7cebc3cd42aca11119f4b0 Mon Sep 17 00:00:00 2001 From: Dhaifallah Alwadani Date: Wed, 28 Jun 2017 16:33:17 +0300 Subject: [PATCH 66/99] Set currencies and fix strings --- num2words/lang_AR.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/num2words/lang_AR.py b/num2words/lang_AR.py index aee780b..a43c968 100644 --- a/num2words/lang_AR.py +++ b/num2words/lang_AR.py @@ -91,12 +91,12 @@ class Num2Word_AR(lang_EU.Num2Word_EU): def to_year(self, val, longval=True): if not (val//100)%10: return self.to_cardinal(val) - return self.to_splitnum(val, hightxt="hundred", jointxt="and", + return self.to_splitnum(val, hightxt="مئة", jointxt="و", longval=longval) def to_currency(self, val, longval=True): - return self.to_splitnum(val, hightxt="dollar/s", lowtxt="cent/s", - jointxt="and", longval=longval, cents = True) + return self.to_splitnum(val, hightxt="ريال", lowtxt="هللة", + jointxt="و", longval=longval, cents = True) n2w = Num2Word_AR() From 39356b495d4fa9e6f40c536e2fa94328ef218fb8 Mon Sep 17 00:00:00 2001 From: Ernesto Rodriguez Ortiz Date: Sun, 2 Jul 2017 19:39:09 -0400 Subject: [PATCH 67/99] v0.5.5 --- CHANGES.rst | 10 ++++++++++ setup.py | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index d9dd429..d7707d2 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,6 +1,16 @@ Changelog ========= +Version 0.5.5 -- 2017/07/02 +--------------------------- + +* Add Arabic localization (#72) +* Add Spanish-Colombian and Spanish-Venezuelan localization (#67) +* Add VietNam localization (#61) +* Add Italian localization (#56, #59) +* Improve Russian localization (#62) +* Improve Polish localization (#58) + Version 0.5.4 -- 2016/10/18 --------------------------- diff --git a/setup.py b/setup.py index 24b4bd2..cad7d41 100644 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ LONG_DESC = open('README.rst', 'rt').read() + '\n\n' + open('CHANGES.rst', 'rt') setup( name='num2words', - version='0.5.4', + version='0.5.5', description='Modules to convert numbers to words. Easily extensible.', long_description=LONG_DESC, license='LGPL', From a659e63eb5ab813fa0de6328285dba92d8fb6d80 Mon Sep 17 00:00:00 2001 From: Tufan Kaynak <31142607+toofun666@users.noreply.github.com> Date: Wed, 30 Aug 2017 19:36:29 +0300 Subject: [PATCH 68/99] TR translation TR translation of num2word reading all cardinals and ordinals up to 10**21-1 --- num2words/__init__.py | 4 +- num2words/lang_TR.py | 575 ++++++++++++++++++++++++++++++++++++++++++ tests/test_tr.py | 104 ++++++++ 3 files changed, 682 insertions(+), 1 deletion(-) create mode 100644 num2words/lang_TR.py create mode 100644 tests/test_tr.py diff --git a/num2words/__init__.py b/num2words/__init__.py index 69ad8db..58eabfb 100644 --- a/num2words/__init__.py +++ b/num2words/__init__.py @@ -37,6 +37,7 @@ from . import lang_IT from . import lang_ES_VE from . import lang_ES_CO from . import lang_VN +from . import lang_TR CONVERTER_CLASSES = { @@ -60,7 +61,8 @@ CONVERTER_CLASSES = { 'pt_BR': lang_PT_BR.Num2Word_PT_BR(), 'he': lang_HE.Num2Word_HE(), 'it': lang_IT.Num2Word_IT(), - 'vi_VN': lang_VN.Num2Word_VN() + 'vi_VN': lang_VN.Num2Word_VN(), + 'tr': lang_TR.Num2Word_TR() } def num2words(number, ordinal=False, lang='en'): diff --git a/num2words/lang_TR.py b/num2words/lang_TR.py new file mode 100644 index 0000000..7b011c1 --- /dev/null +++ b/num2words/lang_TR.py @@ -0,0 +1,575 @@ +# -*- encoding: utf-8 -*- +# Copyright (c) 2003, Taro Ogawa. All Rights Reserved. +# Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. +# Copyright (c) 2017, Tufan Kaynak, Framras. 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 + + +class Num2Word_TR(object): + def __init__(self): + self.precision = 2 + self.negword = u"eksi " + self.pointword = u"virgül" + self.CURRENCY_UNIT = (u"lira",) + self.CURRENCY_SUBUNIT = (u"kuruş",) + # type(%s) not in [long, int, float] + self.errmsg_nonnum = u"Sadece sayılar yazıya çevrilebilir." + # Cannot treat float %s as ordinal. + self.errmsg_floatord = u"Tam sayı olmayan {} sıralamada kullanılamaz." + # Cannot treat negative num %s as ordinal. + self.errmsg_negord = u"Pozitif olmayan {} sıralamada kullanılamaz." + # abs(%s) must be less than %s. + self.errmsg_toobig = u"abs({}) sayı yazıya çevirmek için çok büyük. Yazıya çevrilebilecek en büyük rakam {}." + self.exclude_title = ["et", "virgule", "moins"] + # ordered number tuples in Turkish + self.ORDINAL_SIGN = (",",) + self.CARDINAL_BIRLER = ( + u"sıfır", u"bir", u"iki", u"üç", u"dört", u"beş", u"altı", u"yedi", u"sekiz", u"dokuz",) + self.ORDINAL_BIRLER = ( + u"", u"birinci", u"ikinci", u"üçüncü", u"dördüncü", u"beşinci", u"altıncı", u"yedinci", u"sekizinci", u"dokuzuncu",) + self.CARDINAL_ONLAR = ( + u"", u"on", u"yirmi", u"otuz", u"kırk", u"elli", u"altmış", u"yetmiş", u"seksen", u"doksan",) + self.ORDINAL_ONLAR = ( + u"", u"onuncu", u"yirminci", u"otuzuncu", u"kırkıncı", u"ellinci", u"altmışıncı", u"yetmişinci", u"sekseninci", + u"doksanıncı",) + self.CARDINAL_YUZLER = (u"yüz",) + self.ORDINAL_YUZLER = (u"yüzüncü",) + self.CARDINAL_UCLU_GRUPLAR = (u"", u"bin", u"milyon", u"milyar", u"trilyon", u"katrilyon", u"kentilyon",) + self.ORDINAL_UCLU_GRUPLAR = ( + u"", u"bininci", u"milyonuncu", u"milyarıncı", u"trilyonuncu", u"katrilyonuncu", u"kentilyon",) + self.MAXVAL = (10 ** (len(self.CARDINAL_UCLU_GRUPLAR) * 3)) - 1 + + self.okunacak_tam_sayi = [] + self.okunacak_uclu_grup_sayisi = 0 + self.okunacak_artik_basamak_sayisi = 0 + self.son_sifir_basamagi = 0 + + # def set_numwords(self): + + # def gen_high_numwords(self, units, tens, lows): + + # def set_mid_numwords(self, mid): + + # def set_low_numwords(self, numwords): + + def splitnum(self, value): + return self.to_splitnum(value) + + def to_cardinal(self, value): + oku = "" + is_cardinal = self.verify_cardinal(value) + if is_cardinal: + if not int(value) == value: + return self.to_cardinal_float(value) + self.splitnum(value) + + if self.son_sifir_basamagi >= len(self.okunacak_tam_sayi[0]): + # number like 00 and all 0s and even more, raise error + return oku + + if self.okunacak_uclu_grup_sayisi == 1: + if self.okunacak_artik_basamak_sayisi == 2: + if self.son_sifir_basamagi == 1: + # number like x0, read cardinal x0 and return + oku += self.CARDINAL_ONLAR[int(self.okunacak_tam_sayi[0][0])] + return oku + if self.son_sifir_basamagi == 0: + # number like xy, read cardinal xy and return + oku += self.CARDINAL_ONLAR[int(self.okunacak_tam_sayi[0][0])] + if not self.okunacak_tam_sayi[0][0] == "0": + oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][1])] + return oku + + if self.okunacak_artik_basamak_sayisi == 1: + if self.son_sifir_basamagi == 0: + # number like x, read ordinal x and return + oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] + return oku + + if self.okunacak_artik_basamak_sayisi == 0: + if self.son_sifir_basamagi == 2: + # number like x00, read cardinal x00 and return + if not self.okunacak_tam_sayi[0][0] == "1": + oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] + oku += self.CARDINAL_YUZLER[0] + return oku + if self.son_sifir_basamagi == 1: + # number like xy0, read cardinal xy0 and return + if not self.okunacak_tam_sayi[0][0] == "1": + oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] + oku += self.CARDINAL_YUZLER[0] + oku += self.CARDINAL_ONLAR[int(self.okunacak_tam_sayi[0][1])] + return oku + if self.son_sifir_basamagi == 0: + # number like xyz, read cardinal xyz and return + if not self.okunacak_tam_sayi[0][0] == "1": + oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] + oku += self.CARDINAL_YUZLER[0] + oku += self.CARDINAL_ONLAR[int(self.okunacak_tam_sayi[0][1])] + if not self.okunacak_tam_sayi[0][2] == "0": + oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][2])] + return oku + + if self.okunacak_uclu_grup_sayisi >= 2: + if self.okunacak_artik_basamak_sayisi == 2: + if self.son_sifir_basamagi == len(self.okunacak_tam_sayi[0]) - 1: + # number like x0 and all 0s, read cardinal x0 0..0 and return + oku += self.CARDINAL_ONLAR[int(self.okunacak_tam_sayi[0][0])] + oku += self.CARDINAL_UCLU_GRUPLAR[self.okunacak_uclu_grup_sayisi - 1] + return oku + if self.son_sifir_basamagi == len(self.okunacak_tam_sayi[0]) - 2: + # number like xy and all 0s, read cardinal xy 0..0 and return + oku += self.CARDINAL_ONLAR[int(self.okunacak_tam_sayi[0][0])] + if not self.okunacak_tam_sayi[0][1] == "0": + oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][1])] + oku += self.CARDINAL_UCLU_GRUPLAR[self.okunacak_uclu_grup_sayisi - 1] + return oku + if self.son_sifir_basamagi < len(self.okunacak_tam_sayi[0]) - 2: + # number like xy and others, read cardinal xy n..n and return + oku += self.CARDINAL_ONLAR[int(self.okunacak_tam_sayi[0][0])] + if not self.okunacak_tam_sayi[0][1] == "0": + oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][1])] + oku += self.CARDINAL_UCLU_GRUPLAR[self.okunacak_uclu_grup_sayisi - 1] + + if self.okunacak_artik_basamak_sayisi == 1: + if self.son_sifir_basamagi == len(self.okunacak_tam_sayi[0]) - 1: + # number like x and all 0s, read cardinal x 0..0 and return + if not (self.okunacak_uclu_grup_sayisi == 2 and self.okunacak_tam_sayi[0][0] == "1"): + oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] + oku += self.CARDINAL_UCLU_GRUPLAR[self.okunacak_uclu_grup_sayisi - 1] + return oku + if self.son_sifir_basamagi < len(self.okunacak_tam_sayi[0]) - 1: + # number like x and others, read cardinal x n..n and return + if not (self.okunacak_uclu_grup_sayisi == 2 and self.okunacak_tam_sayi[0][0] == "1"): + oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] + oku += self.CARDINAL_UCLU_GRUPLAR[self.okunacak_uclu_grup_sayisi - 1] + + if self.okunacak_artik_basamak_sayisi == 0: + if self.son_sifir_basamagi == len(self.okunacak_tam_sayi[0]) - 1: + # number like x00 and all 0s, read cardinal x00 0..0 and return + if not self.okunacak_tam_sayi[0][0] == "1": + oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] + oku += self.CARDINAL_YUZLER[0] + oku += self.CARDINAL_UCLU_GRUPLAR[self.okunacak_uclu_grup_sayisi - 1] + return oku + if self.son_sifir_basamagi == len(self.okunacak_tam_sayi[0]) - 2: + # number like xy0 and all 0s, read cardinal xy0 0..0 and return + if not self.okunacak_tam_sayi[0][0] == "1": + oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] + oku += self.CARDINAL_YUZLER[0] + oku += self.CARDINAL_ONLAR[int(self.okunacak_tam_sayi[0][1])] + oku += self.CARDINAL_UCLU_GRUPLAR[self.okunacak_uclu_grup_sayisi - 1] + return oku + if self.son_sifir_basamagi == len(self.okunacak_tam_sayi[0]) - 3: + # number like xyz and all 0s, read cardinal xyz 0..0 and return + if not self.okunacak_tam_sayi[0][0] == "1": + oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] + oku += self.CARDINAL_YUZLER[0] + oku += self.CARDINAL_ONLAR[int(self.okunacak_tam_sayi[0][1])] + if not self.okunacak_tam_sayi[0][2] == "0": + oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][2])] + oku += self.CARDINAL_UCLU_GRUPLAR[self.okunacak_uclu_grup_sayisi - 1] + return oku + if self.son_sifir_basamagi < len(self.okunacak_tam_sayi[0]) - 3: + # number like xyz and all others, read cardinal xyz n..n + if not self.okunacak_tam_sayi[0][0] == "1": + oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] + oku += self.CARDINAL_YUZLER[0] + oku += self.CARDINAL_ONLAR[int(self.okunacak_tam_sayi[0][1])] + if not self.okunacak_tam_sayi[0][2] == "0": + if not (self.okunacak_uclu_grup_sayisi == 2 and self.okunacak_tam_sayi[0][2] == "1"): + oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][2])] + oku += self.CARDINAL_UCLU_GRUPLAR[self.okunacak_uclu_grup_sayisi - 1] + + for i in list(range(self.okunacak_uclu_grup_sayisi - 1, 0, -1)): + okunan_grup_sirasi = self.okunacak_uclu_grup_sayisi - i + if self.okunacak_artik_basamak_sayisi == 0: + son_okunan_basamak_sirasi = okunan_grup_sirasi * 3 + else: + son_okunan_basamak_sirasi = (okunan_grup_sirasi - 1) * 3 + self.okunacak_artik_basamak_sayisi + + if not self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi: son_okunan_basamak_sirasi + 3] == "000": + if not self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi] == "0": + if not self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi] == "1": + oku += self.CARDINAL_BIRLER[ + int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi])] + if self.son_sifir_basamagi == len(self.okunacak_tam_sayi[0]) - ( + son_okunan_basamak_sirasi) - 1: + if i == 1: + oku += self.CARDINAL_YUZLER[0] + return oku + elif i > 1: + oku += self.CARDINAL_YUZLER[0] + oku += self.CARDINAL_UCLU_GRUPLAR[i - 1] + return oku + else: + oku += self.CARDINAL_YUZLER[0] + + if not self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 1] == "0": + if self.son_sifir_basamagi == len(self.okunacak_tam_sayi[0]) - ( + son_okunan_basamak_sirasi) - 2: + if i == 1: + oku += self.CARDINAL_ONLAR[ + int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 1])] + return oku + elif i > 1: + oku += self.CARDINAL_ONLAR[ + int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 1])] + oku += self.CARDINAL_UCLU_GRUPLAR[i - 1] + return oku + else: + oku += self.CARDINAL_ONLAR[ + int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 1])] + + if not self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2] == "0": + if self.son_sifir_basamagi == len(self.okunacak_tam_sayi[0]) - ( + son_okunan_basamak_sirasi) - 3: + if i == 1: + oku += self.CARDINAL_BIRLER[ + int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2])] + return oku + if i == 2: + if not self.okunacak_tam_sayi[0][ + son_okunan_basamak_sirasi: son_okunan_basamak_sirasi + 2] == "00": + oku += self.CARDINAL_BIRLER[ + int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2])] + elif not self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2] == "1": + oku += self.CARDINAL_BIRLER[ + int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2])] + oku += self.CARDINAL_UCLU_GRUPLAR[i - 1] + return oku + if i > 2: + oku += self.CARDINAL_BIRLER[ + int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2])] + oku += self.CARDINAL_UCLU_GRUPLAR[i - 1] + return oku + else: + if not self.okunacak_tam_sayi[0][ + son_okunan_basamak_sirasi: son_okunan_basamak_sirasi + 2] == "00": + oku += self.CARDINAL_BIRLER[ + int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2])] + else: + if i == 2: + if not self.okunacak_tam_sayi[0][ + son_okunan_basamak_sirasi: son_okunan_basamak_sirasi + 2] == "00": + oku += self.CARDINAL_BIRLER[ + int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2])] + elif not self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2] == "1": + oku += self.CARDINAL_BIRLER[ + int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2])] + + oku += self.CARDINAL_UCLU_GRUPLAR[i - 1] + + return oku + + def to_cardinal_float(self, value): + self.splitnum(value) + oku = "" + oku += self.pointword + if len(self.okunacak_tam_sayi[1]) >= 1: + if not self.okunacak_tam_sayi[1][0] == "0": + oku += self.CARDINAL_ONLAR[int(self.okunacak_tam_sayi[1][0])] + if len(self.okunacak_tam_sayi[1]) == 2: + if not self.okunacak_tam_sayi[1][1] == "0": + oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[1][1])] + oku = self.to_cardinal(int(self.okunacak_tam_sayi[0])) + oku + return oku + + # def merge(self, curr, next): + + # def clean(self, val): + + # def title(self, value): + + def verify_cardinal(self, value): + iscardinal = True + try: + if not float(value) == value: + iscardinal = False + except (ValueError, TypeError): + iscardinal = False + raise TypeError(self.errmsg_nonnum) + if abs(value) >= self.MAXVAL: + iscardinal = False + raise OverflowError(self.errmsg_toobig.format(value, self.MAXVAL)) + return iscardinal + + def verify_ordinal(self, value): + isordinal = True + try: + if not int(value) == value: + isordinal = False + if not abs(value) == value: + isordinal = False + raise TypeError(self.errmsg_negord.format(value)) + except (ValueError, TypeError): + isordinal = False + raise TypeError(self.errmsg_nonnum) + if abs(value) >= self.MAXVAL: + isordinal = False + raise OverflowError(self.errmsg_toobig.format(value, self.MAXVAL)) + return isordinal + + # def verify_num(self, value): + + # def set_wordnums(self): + + def to_ordinal(self, value): + oku = "" + isordinal = self.verify_ordinal(value) + if isordinal: + self.splitnum(value) + + if self.son_sifir_basamagi >= len(self.okunacak_tam_sayi[0]): + # number like 00 and all 0s and even more, raise error + return oku + + if self.okunacak_uclu_grup_sayisi == 1: + if self.okunacak_artik_basamak_sayisi == 2: + if self.son_sifir_basamagi == 1: + # number like x0, read ordinal x0 and return + oku += self.ORDINAL_ONLAR[int(self.okunacak_tam_sayi[0][0])] + return oku + if self.son_sifir_basamagi == 0: + # number like xy, read ordinal xy and return + oku += self.CARDINAL_ONLAR[int(self.okunacak_tam_sayi[0][0])] + if not self.okunacak_tam_sayi[0][0] == "0": + oku += self.ORDINAL_BIRLER[int(self.okunacak_tam_sayi[0][1])] + return oku + + if self.okunacak_artik_basamak_sayisi == 1: + if self.son_sifir_basamagi == 0: + # number like x, read ordinal x and return + oku += self.ORDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] + return oku + + if self.okunacak_artik_basamak_sayisi == 0: + if self.son_sifir_basamagi == 2: + # number like x00, read ordinal x00 and return + if not self.okunacak_tam_sayi[0][0] == "1": + oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] + oku += self.ORDINAL_YUZLER[0] + return oku + if self.son_sifir_basamagi == 1: + # number like xy0, read ordinal xy0 and return + if not self.okunacak_tam_sayi[0][0] == "1": + oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] + oku += self.CARDINAL_YUZLER[0] + oku += self.ORDINAL_ONLAR[int(self.okunacak_tam_sayi[0][1])] + return oku + if self.son_sifir_basamagi == 0: + # number like xyz, read ordinal xyz and return + if not self.okunacak_tam_sayi[0][0] == "1": + oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] + oku += self.CARDINAL_YUZLER[0] + oku += self.CARDINAL_ONLAR[int(self.okunacak_tam_sayi[0][1])] + if not self.okunacak_tam_sayi[0][2] == "0": + oku += self.ORDINAL_BIRLER[int(self.okunacak_tam_sayi[0][2])] + return oku + + if self.okunacak_uclu_grup_sayisi >= 2: + if self.okunacak_artik_basamak_sayisi == 2: + if self.son_sifir_basamagi == len(self.okunacak_tam_sayi[0]) - 1: + # number like x0 and all 0s, read ordinal x0 0..0 and return + oku += self.CARDINAL_ONLAR[int(self.okunacak_tam_sayi[0][0])] + oku += self.ORDINAL_UCLU_GRUPLAR[self.okunacak_uclu_grup_sayisi - 1] + return oku + if self.son_sifir_basamagi == len(self.okunacak_tam_sayi[0]) - 2: + # number like xy and all 0s, read ordinal xy 0..0 and return + oku += self.CARDINAL_ONLAR[int(self.okunacak_tam_sayi[0][0])] + if not self.okunacak_tam_sayi[0][1] == "0": + oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][1])] + oku += self.ORDINAL_UCLU_GRUPLAR[self.okunacak_uclu_grup_sayisi - 1] + return oku + if self.son_sifir_basamagi < len(self.okunacak_tam_sayi[0]) - 2: + # number like xy and others, read cardinal xy n..n and return + oku += self.CARDINAL_ONLAR[int(self.okunacak_tam_sayi[0][0])] + if not self.okunacak_tam_sayi[0][1] == "0": + oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][1])] + + oku += self.CARDINAL_UCLU_GRUPLAR[self.okunacak_uclu_grup_sayisi - 1] + + if self.okunacak_artik_basamak_sayisi == 1: + if self.son_sifir_basamagi == len(self.okunacak_tam_sayi[0]) - 1: + # number like x and all 0s, read ordinal x 0..0 and return + if not (self.okunacak_uclu_grup_sayisi == 2 and self.okunacak_tam_sayi[0][0] == "1"): + oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] + oku += self.ORDINAL_UCLU_GRUPLAR[self.okunacak_uclu_grup_sayisi - 1] + return oku + if self.son_sifir_basamagi < len(self.okunacak_tam_sayi[0]) - 1: + # number like x and others, read cardinal x n..n and return + if not (self.okunacak_uclu_grup_sayisi == 2 and self.okunacak_tam_sayi[0][0] == "1"): + oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] + oku += self.CARDINAL_UCLU_GRUPLAR[self.okunacak_uclu_grup_sayisi - 1] + + if self.okunacak_artik_basamak_sayisi == 0: + if self.son_sifir_basamagi == len(self.okunacak_tam_sayi[0]) - 1: + # number like x00 and all 0s, read ordinal x00 0..0 and return + if not self.okunacak_tam_sayi[0][0] == "1": + oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] + oku += self.CARDINAL_YUZLER[0] + oku += self.ORDINAL_UCLU_GRUPLAR[self.okunacak_uclu_grup_sayisi - 1] + return oku + if self.son_sifir_basamagi == len(self.okunacak_tam_sayi[0]) - 2: + # number like xy0 and all 0s, read ordinal xy0 0..0 and return + if not self.okunacak_tam_sayi[0][0] == "1": + oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] + oku += self.CARDINAL_YUZLER[0] + oku += self.CARDINAL_ONLAR[int(self.okunacak_tam_sayi[0][1])] + oku += self.ORDINAL_UCLU_GRUPLAR[self.okunacak_uclu_grup_sayisi - 1] + return oku + if self.son_sifir_basamagi == len(self.okunacak_tam_sayi[0]) - 3: + # number like xyz and all 0s, read ordinal xyz 0..0 and return + if not self.okunacak_tam_sayi[0][0] == "1": + oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] + oku += self.CARDINAL_YUZLER[0] + oku += self.CARDINAL_ONLAR[int(self.okunacak_tam_sayi[0][1])] + if not self.okunacak_tam_sayi[0][2] == "0": + oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][2])] + oku += self.ORDINAL_UCLU_GRUPLAR[self.okunacak_uclu_grup_sayisi - 1] + return oku + if self.son_sifir_basamagi < len(self.okunacak_tam_sayi[0]) - 3: + # number like xyz and all others, read cardinal xyz n..n + if not self.okunacak_tam_sayi[0][0] == "1": + oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] + oku += self.CARDINAL_YUZLER[0] + oku += self.CARDINAL_ONLAR[int(self.okunacak_tam_sayi[0][1])] + if not self.okunacak_tam_sayi[0][2] == "0": + if not (self.okunacak_uclu_grup_sayisi == 2 and self.okunacak_tam_sayi[0][2] == "1"): + oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][2])] + oku += self.CARDINAL_UCLU_GRUPLAR[self.okunacak_uclu_grup_sayisi - 1] + + for i in list(range(self.okunacak_uclu_grup_sayisi - 1, 0, -1)): + okunan_grup_sirasi = self.okunacak_uclu_grup_sayisi - i + if self.okunacak_artik_basamak_sayisi == 0: + son_okunan_basamak_sirasi = okunan_grup_sirasi * 3 + else: + son_okunan_basamak_sirasi = (okunan_grup_sirasi - 1) * 3 + self.okunacak_artik_basamak_sayisi + + if not self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi: son_okunan_basamak_sirasi + 3] == "000": + if not self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi] == "0": + if not self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi] == "1": + oku += self.CARDINAL_BIRLER[ + int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi])] + if self.son_sifir_basamagi == len(self.okunacak_tam_sayi[0]) - ( + son_okunan_basamak_sirasi) - 1: + if i == 1: + oku += self.ORDINAL_YUZLER[0] + return oku + elif i > 1: + oku += self.CARDINAL_YUZLER[0] + oku += self.ORDINAL_UCLU_GRUPLAR[i - 1] + return oku + else: + oku += self.CARDINAL_YUZLER[0] + + if not self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 1] == "0": + if self.son_sifir_basamagi == len(self.okunacak_tam_sayi[0]) - ( + son_okunan_basamak_sirasi) - 2: + if i == 1: + oku += self.ORDINAL_ONLAR[ + int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 1])] + return oku + elif i > 1: + oku += self.CARDINAL_ONLAR[ + int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 1])] + oku += self.ORDINAL_UCLU_GRUPLAR[i - 1] + return oku + else: + oku += self.CARDINAL_ONLAR[ + int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 1])] + + if not self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2] == "0": + if self.son_sifir_basamagi == len(self.okunacak_tam_sayi[0]) - ( + son_okunan_basamak_sirasi) - 3: + if i == 1: + oku += self.ORDINAL_BIRLER[ + int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2])] + return oku + if i == 2: + if not self.okunacak_tam_sayi[0][ + son_okunan_basamak_sirasi: son_okunan_basamak_sirasi + 2] == "00": + oku += self.CARDINAL_BIRLER[ + int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2])] + elif not self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2] == "1": + oku += self.CARDINAL_BIRLER[ + int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2])] + oku += self.ORDINAL_UCLU_GRUPLAR[i - 1] + return oku + if i > 2: + oku += self.CARDINAL_BIRLER[ + int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2])] + oku += self.ORDINAL_UCLU_GRUPLAR[i - 1] + return oku + else: + if not self.okunacak_tam_sayi[0][ + son_okunan_basamak_sirasi: son_okunan_basamak_sirasi + 2] == "00": + oku += self.CARDINAL_BIRLER[ + int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2])] + else: + if not self.okunacak_tam_sayi[0][ + son_okunan_basamak_sirasi: son_okunan_basamak_sirasi + 2] == "00": + oku += self.CARDINAL_BIRLER[ + int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2])] + elif not self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2] == "1": + oku += self.CARDINAL_BIRLER[ + int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2])] + + oku += self.CARDINAL_UCLU_GRUPLAR[i - 1] + + return oku + + def to_ordinal_num(self, value): + oku = "" + isordinal = self.verify_ordinal(value) + if isordinal: + self.splitnum(value) + oku = self.okunacak_tam_sayi[0] + self.ORDINAL_SIGN[0] + + return oku + + # def inflect(self, value, text): + + def to_splitnum(self, val, hightxt="", lowtxt="", jointxt="", divisor=100, longval=True, cents=True): + kesirlibolum = str(int(val * 10**self.precision)) + self.okunacak_tam_sayi = [str(int(val)), kesirlibolum[len(kesirlibolum)-self.precision:]] + if len(self.okunacak_tam_sayi[0]) % 3 > 0: + self.okunacak_uclu_grup_sayisi = (len(self.okunacak_tam_sayi[0]) // 3) + 1 + elif len(self.okunacak_tam_sayi[0]) % 3 == 0: + self.okunacak_uclu_grup_sayisi = len(self.okunacak_tam_sayi[0]) // 3 + self.okunacak_artik_basamak_sayisi = len(self.okunacak_tam_sayi[0]) % 3 + + okunacak = list(self.okunacak_tam_sayi[0][::-1]) + self.son_sifir_basamagi = 0 + found = 0 + for i in range(len(okunacak) - 1): + if int(okunacak[i]) == 0 and found == 0: + self.son_sifir_basamagi = i + 1 + else: + found = 1 + + def to_year(self, value, **kwargs): + return self.to_cardinal(value) + + def to_currency(self, value, **kwargs): + return self.to_cardinal(value) + + # def base_setup(self): + + # def setup(self): + + # def test(self, value): diff --git a/tests/test_tr.py b/tests/test_tr.py new file mode 100644 index 0000000..46210b6 --- /dev/null +++ b/tests/test_tr.py @@ -0,0 +1,104 @@ +# -*- encoding: utf-8 -*- +# Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. +# Copyright (c) 2017, Tufan Kaynak, Framras. 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 unittest import TestCase + +from num2words import num2words + + +class Num2WordsTRTest(TestCase): + def test_tr(self): + # ref https://github.com/savoirfairelinux/num2words/issues/8 + + self.assertEqual(num2words(1, True, "tr"), u"birinci") + self.assertEqual(num2words(2, True, "tr"), u"ikinci") + self.assertEqual(num2words(9, True, "tr"), u"dokuzuncu") + self.assertEqual(num2words(10, True, "tr"), u"onuncu") + self.assertEqual(num2words(11, True, "tr"), u"onbirinci") + self.assertEqual(num2words(44, True, "tr"), u"kırkdördüncü") + self.assertEqual(num2words(100, True, "tr"), u"yüzüncü") + self.assertEqual(num2words(101, True, "tr"), u"yüzbirinci") + self.assertEqual(num2words(103, True, "tr"), u"yüzüçüncü") + self.assertEqual(num2words(110, True, "tr"), u"yüzonuncu") + self.assertEqual(num2words(1000, True, "tr"), u"bininci") + self.assertEqual(num2words(1001, True, "tr"), u"binbirinci") + self.assertEqual(num2words(10000, True, "tr"), u"onbininci") + self.assertEqual(num2words(10100, True, "tr"), u"onbinyüzüncü") + self.assertEqual(num2words(11000, True, "tr"), u"onbirbininci") + self.assertEqual(num2words(35000, True, "tr"), u"otuzbeşbininci") + self.assertEqual(num2words(116331, True, "tr"), u"yüzonaltıbinüçyüzotuzbirinci") + self.assertEqual(num2words(116330, True, "tr"), u"yüzonaltıbinüçyüzotuzuncu") + self.assertEqual(num2words(100000, True, "tr"), u"yüzbininci") + self.assertEqual(num2words(501000, True, "tr"), u"beşyüzbirbininci") + self.assertEqual(num2words(1000111, True, "tr"), u"birmilyonyüzonbirinci") + self.assertEqual(num2words(111000111, True, "tr"), u"yüzonbirmilyonyüzonbirinci") + self.assertEqual(num2words(111001111, True, "tr"), u"yüzonbirmilyonbinyüzonbirinci") + self.assertEqual(num2words(111111111, True, "tr"), u"yüzonbirmilyonyüzonbirbinyüzonbirinci") + self.assertEqual(num2words(100001000, True, "tr"), u"yüzmilyonbininci") + self.assertEqual(num2words(100001001, True, "tr"), u"yüzmilyonbinbirinci") + self.assertEqual(num2words(100010000, True, "tr"), u"yüzmilyononbininci") + self.assertEqual(num2words(100010001, True, "tr"), u"yüzmilyononbinbirinci") + self.assertEqual(num2words(100011000, True, "tr"), u"yüzmilyononbirbininci") + self.assertEqual(num2words(100011001, True, "tr"), u"yüzmilyononbirbinbirinci") + self.assertEqual(num2words(101011001, True, "tr"), u"yüzbirmilyononbirbinbirinci") + self.assertEqual(num2words(101011010, True, "tr"), u"yüzbirmilyononbirbinonuncu") + self.assertEqual(num2words(1101011010, True, "tr"), u"birmilyaryüzbirmilyononbirbinonuncu") + self.assertEqual(num2words(101101011010, True, "tr"), u"yüzbirmilyaryüzbirmilyononbirbinonuncu") + self.assertEqual(num2words(1000000000001, True, "tr"), u"birtrilyonbirinci") + + self.assertEqual(num2words(1, False, "tr"), u"bir") + self.assertEqual(num2words(2, False, "tr"), u"iki") + self.assertEqual(num2words(9, False, "tr"), u"dokuz") + self.assertEqual(num2words(10, False, "tr"), u"on") + self.assertEqual(num2words(11, False, "tr"), u"onbir") + self.assertEqual(num2words(44, False, "tr"), u"kırkdört") + self.assertEqual(num2words(100, False, "tr"), u"yüz") + self.assertEqual(num2words(101, False, "tr"), u"yüzbir") + self.assertEqual(num2words(103, False, "tr"), u"yüzüç") + self.assertEqual(num2words(110, False, "tr"), u"yüzon") + self.assertEqual(num2words(1000, False, "tr"), u"bin") + self.assertEqual(num2words(1001, False, "tr"), u"binbir") + self.assertEqual(num2words(10000, False, "tr"), u"onbin") + self.assertEqual(num2words(10100, False, "tr"), u"onbinyüz") + self.assertEqual(num2words(11000, False, "tr"), u"onbirbin") + self.assertEqual(num2words(35000, False, "tr"), u"otuzbeşbin") + self.assertEqual(num2words(116331, False, "tr"), u"yüzonaltıbinüçyüzotuzbir") + self.assertEqual(num2words(116330, False, "tr"), u"yüzonaltıbinüçyüzotuz") + self.assertEqual(num2words(500000, False, "tr"), u"beşyüzbin") + self.assertEqual(num2words(501000, False, "tr"), u"beşyüzbirbin") + self.assertEqual(num2words(1000111, False, "tr"), u"birmilyonyüzonbir") + self.assertEqual(num2words(111000111, False, "tr"), u"yüzonbirmilyonyüzonbir") + self.assertEqual(num2words(111001111, False, "tr"), u"yüzonbirmilyonbinyüzonbir") + self.assertEqual(num2words(111111111, False, "tr"), u"yüzonbirmilyonyüzonbirbinyüzonbir") + self.assertEqual(num2words(100001000, False, "tr"), u"yüzmilyonbin") + self.assertEqual(num2words(100001001, False, "tr"), u"yüzmilyonbinbir") + self.assertEqual(num2words(100010000, False, "tr"), u"yüzmilyononbin") + self.assertEqual(num2words(100010001, False, "tr"), u"yüzmilyononbinbir") + self.assertEqual(num2words(100011000, False, "tr"), u"yüzmilyononbirbin") + self.assertEqual(num2words(100011001, False, "tr"), u"yüzmilyononbirbinbir") + self.assertEqual(num2words(101011001, False, "tr"), u"yüzbirmilyononbirbinbir") + self.assertEqual(num2words(101011010, False, "tr"), u"yüzbirmilyononbirbinon") + self.assertEqual(num2words(1101011010, False, "tr"), u"birmilyaryüzbirmilyononbirbinon") + self.assertEqual(num2words(101101011010, False, "tr"), u"yüzbirmilyaryüzbirmilyononbirbinon") + self.assertEqual(num2words(1000000000001, False, "tr"), u"birtrilyonbir") + self.assertEqual(num2words(0.1, False, "tr"), u"sıfırvirgülon") + self.assertEqual(num2words(0.21, False, "tr"), u"sıfırvirgülyirmibir") + self.assertEqual(num2words(1.01, False, "tr"), u"birvirgülbir") + self.assertEqual(num2words(1.1, False, "tr"), u"birvirgülon") + self.assertEqual(num2words(1.21, False, "tr"), u"birvirgülyirmibir") + self.assertEqual(num2words(101101011010.02, False, "tr"), u"yüzbirmilyaryüzbirmilyononbirbinonvirgüliki") + self.assertEqual(num2words(101101011010.2, False, "tr"), u"yüzbirmilyaryüzbirmilyononbirbinonvirgülyirmi") From 969c5daf9b971817ae9f84d01038b0763a1593d0 Mon Sep 17 00:00:00 2001 From: Tufan Kaynak <31142607+toofun666@users.noreply.github.com> Date: Fri, 1 Sep 2017 00:46:23 +0300 Subject: [PATCH 69/99] var names changed to English --- num2words/lang_TR.py | 604 +++++++++++++++++++++---------------------- 1 file changed, 302 insertions(+), 302 deletions(-) diff --git a/num2words/lang_TR.py b/num2words/lang_TR.py index 7b011c1..45add35 100644 --- a/num2words/lang_TR.py +++ b/num2words/lang_TR.py @@ -22,7 +22,7 @@ from __future__ import unicode_literals class Num2Word_TR(object): def __init__(self): self.precision = 2 - self.negword = u"eksi " + self.negword = u"eksi" self.pointword = u"virgül" self.CURRENCY_UNIT = (u"lira",) self.CURRENCY_SUBUNIT = (u"kuruş",) @@ -37,26 +37,27 @@ class Num2Word_TR(object): self.exclude_title = ["et", "virgule", "moins"] # ordered number tuples in Turkish self.ORDINAL_SIGN = (",",) - self.CARDINAL_BIRLER = ( + self.CARDINAL_ONES = ( u"sıfır", u"bir", u"iki", u"üç", u"dört", u"beş", u"altı", u"yedi", u"sekiz", u"dokuz",) - self.ORDINAL_BIRLER = ( - u"", u"birinci", u"ikinci", u"üçüncü", u"dördüncü", u"beşinci", u"altıncı", u"yedinci", u"sekizinci", u"dokuzuncu",) - self.CARDINAL_ONLAR = ( + self.ORDINAL_ONES = ( + u"", u"birinci", u"ikinci", u"üçüncü", u"dördüncü", u"beşinci", u"altıncı", u"yedinci", u"sekizinci", + u"dokuzuncu",) + self.CARDINAL_TEN = ( u"", u"on", u"yirmi", u"otuz", u"kırk", u"elli", u"altmış", u"yetmiş", u"seksen", u"doksan",) - self.ORDINAL_ONLAR = ( - u"", u"onuncu", u"yirminci", u"otuzuncu", u"kırkıncı", u"ellinci", u"altmışıncı", u"yetmişinci", u"sekseninci", - u"doksanıncı",) - self.CARDINAL_YUZLER = (u"yüz",) - self.ORDINAL_YUZLER = (u"yüzüncü",) - self.CARDINAL_UCLU_GRUPLAR = (u"", u"bin", u"milyon", u"milyar", u"trilyon", u"katrilyon", u"kentilyon",) - self.ORDINAL_UCLU_GRUPLAR = ( + self.ORDINAL_TENS = ( + u"", u"onuncu", u"yirminci", u"otuzuncu", u"kırkıncı", u"ellinci", u"altmışıncı", u"yetmişinci", + u"sekseninci", u"doksanıncı",) + self.CARDINAL_HUNDREDS = (u"yüz",) + self.ORDINAL_HUNDREDS = (u"yüzüncü",) + self.CARDINAL_TRIPLETS = (u"", u"bin", u"milyon", u"milyar", u"trilyon", u"katrilyon", u"kentilyon",) + self.ORDINAL_TRIPLETS = ( u"", u"bininci", u"milyonuncu", u"milyarıncı", u"trilyonuncu", u"katrilyonuncu", u"kentilyon",) - self.MAXVAL = (10 ** (len(self.CARDINAL_UCLU_GRUPLAR) * 3)) - 1 + self.MAXVAL = (10 ** (len(self.CARDINAL_TRIPLETS) * 3)) - 1 - self.okunacak_tam_sayi = [] - self.okunacak_uclu_grup_sayisi = 0 - self.okunacak_artik_basamak_sayisi = 0 - self.son_sifir_basamagi = 0 + self.integers_to_read = [] + self.total_triplets_to_read = 0 + self.total_digits_outside_triplets = 0 + self.order_of_last_zero_digit = 0 # def set_numwords(self): @@ -77,202 +78,202 @@ class Num2Word_TR(object): return self.to_cardinal_float(value) self.splitnum(value) - if self.son_sifir_basamagi >= len(self.okunacak_tam_sayi[0]): + if self.order_of_last_zero_digit >= len(self.integers_to_read[0]): # number like 00 and all 0s and even more, raise error return oku - if self.okunacak_uclu_grup_sayisi == 1: - if self.okunacak_artik_basamak_sayisi == 2: - if self.son_sifir_basamagi == 1: + if self.total_triplets_to_read == 1: + if self.total_digits_outside_triplets == 2: + if self.order_of_last_zero_digit == 1: # number like x0, read cardinal x0 and return - oku += self.CARDINAL_ONLAR[int(self.okunacak_tam_sayi[0][0])] + oku += self.CARDINAL_TEN[int(self.integers_to_read[0][0])] return oku - if self.son_sifir_basamagi == 0: + if self.order_of_last_zero_digit == 0: # number like xy, read cardinal xy and return - oku += self.CARDINAL_ONLAR[int(self.okunacak_tam_sayi[0][0])] - if not self.okunacak_tam_sayi[0][0] == "0": - oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][1])] + oku += self.CARDINAL_TEN[int(self.integers_to_read[0][0])] + if not self.integers_to_read[0][0] == "0": + oku += self.CARDINAL_ONES[int(self.integers_to_read[0][1])] return oku - if self.okunacak_artik_basamak_sayisi == 1: - if self.son_sifir_basamagi == 0: + if self.total_digits_outside_triplets == 1: + if self.order_of_last_zero_digit == 0: # number like x, read ordinal x and return - oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] + oku += self.CARDINAL_ONES[int(self.integers_to_read[0][0])] return oku - if self.okunacak_artik_basamak_sayisi == 0: - if self.son_sifir_basamagi == 2: + if self.total_digits_outside_triplets == 0: + if self.order_of_last_zero_digit == 2: # number like x00, read cardinal x00 and return - if not self.okunacak_tam_sayi[0][0] == "1": - oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] - oku += self.CARDINAL_YUZLER[0] + if not self.integers_to_read[0][0] == "1": + oku += self.CARDINAL_ONES[int(self.integers_to_read[0][0])] + oku += self.CARDINAL_HUNDREDS[0] return oku - if self.son_sifir_basamagi == 1: + if self.order_of_last_zero_digit == 1: # number like xy0, read cardinal xy0 and return - if not self.okunacak_tam_sayi[0][0] == "1": - oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] - oku += self.CARDINAL_YUZLER[0] - oku += self.CARDINAL_ONLAR[int(self.okunacak_tam_sayi[0][1])] + if not self.integers_to_read[0][0] == "1": + oku += self.CARDINAL_ONES[int(self.integers_to_read[0][0])] + oku += self.CARDINAL_HUNDREDS[0] + oku += self.CARDINAL_TEN[int(self.integers_to_read[0][1])] return oku - if self.son_sifir_basamagi == 0: + if self.order_of_last_zero_digit == 0: # number like xyz, read cardinal xyz and return - if not self.okunacak_tam_sayi[0][0] == "1": - oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] - oku += self.CARDINAL_YUZLER[0] - oku += self.CARDINAL_ONLAR[int(self.okunacak_tam_sayi[0][1])] - if not self.okunacak_tam_sayi[0][2] == "0": - oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][2])] + if not self.integers_to_read[0][0] == "1": + oku += self.CARDINAL_ONES[int(self.integers_to_read[0][0])] + oku += self.CARDINAL_HUNDREDS[0] + oku += self.CARDINAL_TEN[int(self.integers_to_read[0][1])] + if not self.integers_to_read[0][2] == "0": + oku += self.CARDINAL_ONES[int(self.integers_to_read[0][2])] return oku - if self.okunacak_uclu_grup_sayisi >= 2: - if self.okunacak_artik_basamak_sayisi == 2: - if self.son_sifir_basamagi == len(self.okunacak_tam_sayi[0]) - 1: + if self.total_triplets_to_read >= 2: + if self.total_digits_outside_triplets == 2: + if self.order_of_last_zero_digit == len(self.integers_to_read[0]) - 1: # number like x0 and all 0s, read cardinal x0 0..0 and return - oku += self.CARDINAL_ONLAR[int(self.okunacak_tam_sayi[0][0])] - oku += self.CARDINAL_UCLU_GRUPLAR[self.okunacak_uclu_grup_sayisi - 1] + oku += self.CARDINAL_TEN[int(self.integers_to_read[0][0])] + oku += self.CARDINAL_TRIPLETS[self.total_triplets_to_read - 1] return oku - if self.son_sifir_basamagi == len(self.okunacak_tam_sayi[0]) - 2: + if self.order_of_last_zero_digit == len(self.integers_to_read[0]) - 2: # number like xy and all 0s, read cardinal xy 0..0 and return - oku += self.CARDINAL_ONLAR[int(self.okunacak_tam_sayi[0][0])] - if not self.okunacak_tam_sayi[0][1] == "0": - oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][1])] - oku += self.CARDINAL_UCLU_GRUPLAR[self.okunacak_uclu_grup_sayisi - 1] + oku += self.CARDINAL_TEN[int(self.integers_to_read[0][0])] + if not self.integers_to_read[0][1] == "0": + oku += self.CARDINAL_ONES[int(self.integers_to_read[0][1])] + oku += self.CARDINAL_TRIPLETS[self.total_triplets_to_read - 1] return oku - if self.son_sifir_basamagi < len(self.okunacak_tam_sayi[0]) - 2: + if self.order_of_last_zero_digit < len(self.integers_to_read[0]) - 2: # number like xy and others, read cardinal xy n..n and return - oku += self.CARDINAL_ONLAR[int(self.okunacak_tam_sayi[0][0])] - if not self.okunacak_tam_sayi[0][1] == "0": - oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][1])] - oku += self.CARDINAL_UCLU_GRUPLAR[self.okunacak_uclu_grup_sayisi - 1] + oku += self.CARDINAL_TEN[int(self.integers_to_read[0][0])] + if not self.integers_to_read[0][1] == "0": + oku += self.CARDINAL_ONES[int(self.integers_to_read[0][1])] + oku += self.CARDINAL_TRIPLETS[self.total_triplets_to_read - 1] - if self.okunacak_artik_basamak_sayisi == 1: - if self.son_sifir_basamagi == len(self.okunacak_tam_sayi[0]) - 1: + if self.total_digits_outside_triplets == 1: + if self.order_of_last_zero_digit == len(self.integers_to_read[0]) - 1: # number like x and all 0s, read cardinal x 0..0 and return - if not (self.okunacak_uclu_grup_sayisi == 2 and self.okunacak_tam_sayi[0][0] == "1"): - oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] - oku += self.CARDINAL_UCLU_GRUPLAR[self.okunacak_uclu_grup_sayisi - 1] + if not (self.total_triplets_to_read == 2 and self.integers_to_read[0][0] == "1"): + oku += self.CARDINAL_ONES[int(self.integers_to_read[0][0])] + oku += self.CARDINAL_TRIPLETS[self.total_triplets_to_read - 1] return oku - if self.son_sifir_basamagi < len(self.okunacak_tam_sayi[0]) - 1: + if self.order_of_last_zero_digit < len(self.integers_to_read[0]) - 1: # number like x and others, read cardinal x n..n and return - if not (self.okunacak_uclu_grup_sayisi == 2 and self.okunacak_tam_sayi[0][0] == "1"): - oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] - oku += self.CARDINAL_UCLU_GRUPLAR[self.okunacak_uclu_grup_sayisi - 1] + if not (self.total_triplets_to_read == 2 and self.integers_to_read[0][0] == "1"): + oku += self.CARDINAL_ONES[int(self.integers_to_read[0][0])] + oku += self.CARDINAL_TRIPLETS[self.total_triplets_to_read - 1] - if self.okunacak_artik_basamak_sayisi == 0: - if self.son_sifir_basamagi == len(self.okunacak_tam_sayi[0]) - 1: + if self.total_digits_outside_triplets == 0: + if self.order_of_last_zero_digit == len(self.integers_to_read[0]) - 1: # number like x00 and all 0s, read cardinal x00 0..0 and return - if not self.okunacak_tam_sayi[0][0] == "1": - oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] - oku += self.CARDINAL_YUZLER[0] - oku += self.CARDINAL_UCLU_GRUPLAR[self.okunacak_uclu_grup_sayisi - 1] + if not self.integers_to_read[0][0] == "1": + oku += self.CARDINAL_ONES[int(self.integers_to_read[0][0])] + oku += self.CARDINAL_HUNDREDS[0] + oku += self.CARDINAL_TRIPLETS[self.total_triplets_to_read - 1] return oku - if self.son_sifir_basamagi == len(self.okunacak_tam_sayi[0]) - 2: + if self.order_of_last_zero_digit == len(self.integers_to_read[0]) - 2: # number like xy0 and all 0s, read cardinal xy0 0..0 and return - if not self.okunacak_tam_sayi[0][0] == "1": - oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] - oku += self.CARDINAL_YUZLER[0] - oku += self.CARDINAL_ONLAR[int(self.okunacak_tam_sayi[0][1])] - oku += self.CARDINAL_UCLU_GRUPLAR[self.okunacak_uclu_grup_sayisi - 1] + if not self.integers_to_read[0][0] == "1": + oku += self.CARDINAL_ONES[int(self.integers_to_read[0][0])] + oku += self.CARDINAL_HUNDREDS[0] + oku += self.CARDINAL_TEN[int(self.integers_to_read[0][1])] + oku += self.CARDINAL_TRIPLETS[self.total_triplets_to_read - 1] return oku - if self.son_sifir_basamagi == len(self.okunacak_tam_sayi[0]) - 3: + if self.order_of_last_zero_digit == len(self.integers_to_read[0]) - 3: # number like xyz and all 0s, read cardinal xyz 0..0 and return - if not self.okunacak_tam_sayi[0][0] == "1": - oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] - oku += self.CARDINAL_YUZLER[0] - oku += self.CARDINAL_ONLAR[int(self.okunacak_tam_sayi[0][1])] - if not self.okunacak_tam_sayi[0][2] == "0": - oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][2])] - oku += self.CARDINAL_UCLU_GRUPLAR[self.okunacak_uclu_grup_sayisi - 1] + if not self.integers_to_read[0][0] == "1": + oku += self.CARDINAL_ONES[int(self.integers_to_read[0][0])] + oku += self.CARDINAL_HUNDREDS[0] + oku += self.CARDINAL_TEN[int(self.integers_to_read[0][1])] + if not self.integers_to_read[0][2] == "0": + oku += self.CARDINAL_ONES[int(self.integers_to_read[0][2])] + oku += self.CARDINAL_TRIPLETS[self.total_triplets_to_read - 1] return oku - if self.son_sifir_basamagi < len(self.okunacak_tam_sayi[0]) - 3: + if self.order_of_last_zero_digit < len(self.integers_to_read[0]) - 3: # number like xyz and all others, read cardinal xyz n..n - if not self.okunacak_tam_sayi[0][0] == "1": - oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] - oku += self.CARDINAL_YUZLER[0] - oku += self.CARDINAL_ONLAR[int(self.okunacak_tam_sayi[0][1])] - if not self.okunacak_tam_sayi[0][2] == "0": - if not (self.okunacak_uclu_grup_sayisi == 2 and self.okunacak_tam_sayi[0][2] == "1"): - oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][2])] - oku += self.CARDINAL_UCLU_GRUPLAR[self.okunacak_uclu_grup_sayisi - 1] + if not self.integers_to_read[0][0] == "1": + oku += self.CARDINAL_ONES[int(self.integers_to_read[0][0])] + oku += self.CARDINAL_HUNDREDS[0] + oku += self.CARDINAL_TEN[int(self.integers_to_read[0][1])] + if not self.integers_to_read[0][2] == "0": + if not (self.total_triplets_to_read == 2 and self.integers_to_read[0][2] == "1"): + oku += self.CARDINAL_ONES[int(self.integers_to_read[0][2])] + oku += self.CARDINAL_TRIPLETS[self.total_triplets_to_read - 1] - for i in list(range(self.okunacak_uclu_grup_sayisi - 1, 0, -1)): - okunan_grup_sirasi = self.okunacak_uclu_grup_sayisi - i - if self.okunacak_artik_basamak_sayisi == 0: + for i in list(range(self.total_triplets_to_read - 1, 0, -1)): + okunan_grup_sirasi = self.total_triplets_to_read - i + if self.total_digits_outside_triplets == 0: son_okunan_basamak_sirasi = okunan_grup_sirasi * 3 else: - son_okunan_basamak_sirasi = (okunan_grup_sirasi - 1) * 3 + self.okunacak_artik_basamak_sayisi + son_okunan_basamak_sirasi = (okunan_grup_sirasi - 1) * 3 + self.total_digits_outside_triplets - if not self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi: son_okunan_basamak_sirasi + 3] == "000": - if not self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi] == "0": - if not self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi] == "1": - oku += self.CARDINAL_BIRLER[ - int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi])] - if self.son_sifir_basamagi == len(self.okunacak_tam_sayi[0]) - ( + if not self.integers_to_read[0][son_okunan_basamak_sirasi: son_okunan_basamak_sirasi + 3] == "000": + if not self.integers_to_read[0][son_okunan_basamak_sirasi] == "0": + if not self.integers_to_read[0][son_okunan_basamak_sirasi] == "1": + oku += self.CARDINAL_ONES[ + int(self.integers_to_read[0][son_okunan_basamak_sirasi])] + if self.order_of_last_zero_digit == len(self.integers_to_read[0]) - ( son_okunan_basamak_sirasi) - 1: if i == 1: - oku += self.CARDINAL_YUZLER[0] + oku += self.CARDINAL_HUNDREDS[0] return oku elif i > 1: - oku += self.CARDINAL_YUZLER[0] - oku += self.CARDINAL_UCLU_GRUPLAR[i - 1] + oku += self.CARDINAL_HUNDREDS[0] + oku += self.CARDINAL_TRIPLETS[i - 1] return oku else: - oku += self.CARDINAL_YUZLER[0] + oku += self.CARDINAL_HUNDREDS[0] - if not self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 1] == "0": - if self.son_sifir_basamagi == len(self.okunacak_tam_sayi[0]) - ( + if not self.integers_to_read[0][son_okunan_basamak_sirasi + 1] == "0": + if self.order_of_last_zero_digit == len(self.integers_to_read[0]) - ( son_okunan_basamak_sirasi) - 2: if i == 1: - oku += self.CARDINAL_ONLAR[ - int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 1])] + oku += self.CARDINAL_TEN[ + int(self.integers_to_read[0][son_okunan_basamak_sirasi + 1])] return oku elif i > 1: - oku += self.CARDINAL_ONLAR[ - int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 1])] - oku += self.CARDINAL_UCLU_GRUPLAR[i - 1] + oku += self.CARDINAL_TEN[ + int(self.integers_to_read[0][son_okunan_basamak_sirasi + 1])] + oku += self.CARDINAL_TRIPLETS[i - 1] return oku else: - oku += self.CARDINAL_ONLAR[ - int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 1])] + oku += self.CARDINAL_TEN[ + int(self.integers_to_read[0][son_okunan_basamak_sirasi + 1])] - if not self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2] == "0": - if self.son_sifir_basamagi == len(self.okunacak_tam_sayi[0]) - ( + if not self.integers_to_read[0][son_okunan_basamak_sirasi + 2] == "0": + if self.order_of_last_zero_digit == len(self.integers_to_read[0]) - ( son_okunan_basamak_sirasi) - 3: if i == 1: - oku += self.CARDINAL_BIRLER[ - int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2])] + oku += self.CARDINAL_ONES[ + int(self.integers_to_read[0][son_okunan_basamak_sirasi + 2])] return oku if i == 2: - if not self.okunacak_tam_sayi[0][ + if not self.integers_to_read[0][ son_okunan_basamak_sirasi: son_okunan_basamak_sirasi + 2] == "00": - oku += self.CARDINAL_BIRLER[ - int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2])] - elif not self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2] == "1": - oku += self.CARDINAL_BIRLER[ - int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2])] - oku += self.CARDINAL_UCLU_GRUPLAR[i - 1] + oku += self.CARDINAL_ONES[ + int(self.integers_to_read[0][son_okunan_basamak_sirasi + 2])] + elif not self.integers_to_read[0][son_okunan_basamak_sirasi + 2] == "1": + oku += self.CARDINAL_ONES[ + int(self.integers_to_read[0][son_okunan_basamak_sirasi + 2])] + oku += self.CARDINAL_TRIPLETS[i - 1] return oku if i > 2: - oku += self.CARDINAL_BIRLER[ - int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2])] - oku += self.CARDINAL_UCLU_GRUPLAR[i - 1] + oku += self.CARDINAL_ONES[ + int(self.integers_to_read[0][son_okunan_basamak_sirasi + 2])] + oku += self.CARDINAL_TRIPLETS[i - 1] return oku else: - if not self.okunacak_tam_sayi[0][ + if not self.integers_to_read[0][ son_okunan_basamak_sirasi: son_okunan_basamak_sirasi + 2] == "00": - oku += self.CARDINAL_BIRLER[ - int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2])] + oku += self.CARDINAL_ONES[ + int(self.integers_to_read[0][son_okunan_basamak_sirasi + 2])] else: if i == 2: - if not self.okunacak_tam_sayi[0][ + if not self.integers_to_read[0][ son_okunan_basamak_sirasi: son_okunan_basamak_sirasi + 2] == "00": - oku += self.CARDINAL_BIRLER[ - int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2])] - elif not self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2] == "1": - oku += self.CARDINAL_BIRLER[ - int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2])] + oku += self.CARDINAL_ONES[ + int(self.integers_to_read[0][son_okunan_basamak_sirasi + 2])] + elif not self.integers_to_read[0][son_okunan_basamak_sirasi + 2] == "1": + oku += self.CARDINAL_ONES[ + int(self.integers_to_read[0][son_okunan_basamak_sirasi + 2])] - oku += self.CARDINAL_UCLU_GRUPLAR[i - 1] + oku += self.CARDINAL_TRIPLETS[i - 1] return oku @@ -280,13 +281,13 @@ class Num2Word_TR(object): self.splitnum(value) oku = "" oku += self.pointword - if len(self.okunacak_tam_sayi[1]) >= 1: - if not self.okunacak_tam_sayi[1][0] == "0": - oku += self.CARDINAL_ONLAR[int(self.okunacak_tam_sayi[1][0])] - if len(self.okunacak_tam_sayi[1]) == 2: - if not self.okunacak_tam_sayi[1][1] == "0": - oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[1][1])] - oku = self.to_cardinal(int(self.okunacak_tam_sayi[0])) + oku + if len(self.integers_to_read[1]) >= 1: + if not self.integers_to_read[1][0] == "0": + oku += self.CARDINAL_TEN[int(self.integers_to_read[1][0])] + if len(self.integers_to_read[1]) == 2: + if not self.integers_to_read[1][1] == "0": + oku += self.CARDINAL_ONES[int(self.integers_to_read[1][1])] + oku = self.to_cardinal(int(self.integers_to_read[0])) + oku return oku # def merge(self, curr, next): @@ -301,10 +302,8 @@ class Num2Word_TR(object): if not float(value) == value: iscardinal = False except (ValueError, TypeError): - iscardinal = False raise TypeError(self.errmsg_nonnum) if abs(value) >= self.MAXVAL: - iscardinal = False raise OverflowError(self.errmsg_toobig.format(value, self.MAXVAL)) return iscardinal @@ -314,13 +313,10 @@ class Num2Word_TR(object): if not int(value) == value: isordinal = False if not abs(value) == value: - isordinal = False raise TypeError(self.errmsg_negord.format(value)) except (ValueError, TypeError): - isordinal = False raise TypeError(self.errmsg_nonnum) if abs(value) >= self.MAXVAL: - isordinal = False raise OverflowError(self.errmsg_toobig.format(value, self.MAXVAL)) return isordinal @@ -334,202 +330,202 @@ class Num2Word_TR(object): if isordinal: self.splitnum(value) - if self.son_sifir_basamagi >= len(self.okunacak_tam_sayi[0]): + if self.order_of_last_zero_digit >= len(self.integers_to_read[0]): # number like 00 and all 0s and even more, raise error return oku - if self.okunacak_uclu_grup_sayisi == 1: - if self.okunacak_artik_basamak_sayisi == 2: - if self.son_sifir_basamagi == 1: + if self.total_triplets_to_read == 1: + if self.total_digits_outside_triplets == 2: + if self.order_of_last_zero_digit == 1: # number like x0, read ordinal x0 and return - oku += self.ORDINAL_ONLAR[int(self.okunacak_tam_sayi[0][0])] + oku += self.ORDINAL_TENS[int(self.integers_to_read[0][0])] return oku - if self.son_sifir_basamagi == 0: + if self.order_of_last_zero_digit == 0: # number like xy, read ordinal xy and return - oku += self.CARDINAL_ONLAR[int(self.okunacak_tam_sayi[0][0])] - if not self.okunacak_tam_sayi[0][0] == "0": - oku += self.ORDINAL_BIRLER[int(self.okunacak_tam_sayi[0][1])] + oku += self.CARDINAL_TEN[int(self.integers_to_read[0][0])] + if not self.integers_to_read[0][0] == "0": + oku += self.ORDINAL_ONES[int(self.integers_to_read[0][1])] return oku - if self.okunacak_artik_basamak_sayisi == 1: - if self.son_sifir_basamagi == 0: + if self.total_digits_outside_triplets == 1: + if self.order_of_last_zero_digit == 0: # number like x, read ordinal x and return - oku += self.ORDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] + oku += self.ORDINAL_ONES[int(self.integers_to_read[0][0])] return oku - if self.okunacak_artik_basamak_sayisi == 0: - if self.son_sifir_basamagi == 2: + if self.total_digits_outside_triplets == 0: + if self.order_of_last_zero_digit == 2: # number like x00, read ordinal x00 and return - if not self.okunacak_tam_sayi[0][0] == "1": - oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] - oku += self.ORDINAL_YUZLER[0] + if not self.integers_to_read[0][0] == "1": + oku += self.CARDINAL_ONES[int(self.integers_to_read[0][0])] + oku += self.ORDINAL_HUNDREDS[0] return oku - if self.son_sifir_basamagi == 1: + if self.order_of_last_zero_digit == 1: # number like xy0, read ordinal xy0 and return - if not self.okunacak_tam_sayi[0][0] == "1": - oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] - oku += self.CARDINAL_YUZLER[0] - oku += self.ORDINAL_ONLAR[int(self.okunacak_tam_sayi[0][1])] + if not self.integers_to_read[0][0] == "1": + oku += self.CARDINAL_ONES[int(self.integers_to_read[0][0])] + oku += self.CARDINAL_HUNDREDS[0] + oku += self.ORDINAL_TENS[int(self.integers_to_read[0][1])] return oku - if self.son_sifir_basamagi == 0: + if self.order_of_last_zero_digit == 0: # number like xyz, read ordinal xyz and return - if not self.okunacak_tam_sayi[0][0] == "1": - oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] - oku += self.CARDINAL_YUZLER[0] - oku += self.CARDINAL_ONLAR[int(self.okunacak_tam_sayi[0][1])] - if not self.okunacak_tam_sayi[0][2] == "0": - oku += self.ORDINAL_BIRLER[int(self.okunacak_tam_sayi[0][2])] + if not self.integers_to_read[0][0] == "1": + oku += self.CARDINAL_ONES[int(self.integers_to_read[0][0])] + oku += self.CARDINAL_HUNDREDS[0] + oku += self.CARDINAL_TEN[int(self.integers_to_read[0][1])] + if not self.integers_to_read[0][2] == "0": + oku += self.ORDINAL_ONES[int(self.integers_to_read[0][2])] return oku - if self.okunacak_uclu_grup_sayisi >= 2: - if self.okunacak_artik_basamak_sayisi == 2: - if self.son_sifir_basamagi == len(self.okunacak_tam_sayi[0]) - 1: + if self.total_triplets_to_read >= 2: + if self.total_digits_outside_triplets == 2: + if self.order_of_last_zero_digit == len(self.integers_to_read[0]) - 1: # number like x0 and all 0s, read ordinal x0 0..0 and return - oku += self.CARDINAL_ONLAR[int(self.okunacak_tam_sayi[0][0])] - oku += self.ORDINAL_UCLU_GRUPLAR[self.okunacak_uclu_grup_sayisi - 1] + oku += self.CARDINAL_TEN[int(self.integers_to_read[0][0])] + oku += self.ORDINAL_TRIPLETS[self.total_triplets_to_read - 1] return oku - if self.son_sifir_basamagi == len(self.okunacak_tam_sayi[0]) - 2: + if self.order_of_last_zero_digit == len(self.integers_to_read[0]) - 2: # number like xy and all 0s, read ordinal xy 0..0 and return - oku += self.CARDINAL_ONLAR[int(self.okunacak_tam_sayi[0][0])] - if not self.okunacak_tam_sayi[0][1] == "0": - oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][1])] - oku += self.ORDINAL_UCLU_GRUPLAR[self.okunacak_uclu_grup_sayisi - 1] + oku += self.CARDINAL_TEN[int(self.integers_to_read[0][0])] + if not self.integers_to_read[0][1] == "0": + oku += self.CARDINAL_ONES[int(self.integers_to_read[0][1])] + oku += self.ORDINAL_TRIPLETS[self.total_triplets_to_read - 1] return oku - if self.son_sifir_basamagi < len(self.okunacak_tam_sayi[0]) - 2: + if self.order_of_last_zero_digit < len(self.integers_to_read[0]) - 2: # number like xy and others, read cardinal xy n..n and return - oku += self.CARDINAL_ONLAR[int(self.okunacak_tam_sayi[0][0])] - if not self.okunacak_tam_sayi[0][1] == "0": - oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][1])] + oku += self.CARDINAL_TEN[int(self.integers_to_read[0][0])] + if not self.integers_to_read[0][1] == "0": + oku += self.CARDINAL_ONES[int(self.integers_to_read[0][1])] - oku += self.CARDINAL_UCLU_GRUPLAR[self.okunacak_uclu_grup_sayisi - 1] + oku += self.CARDINAL_TRIPLETS[self.total_triplets_to_read - 1] - if self.okunacak_artik_basamak_sayisi == 1: - if self.son_sifir_basamagi == len(self.okunacak_tam_sayi[0]) - 1: + if self.total_digits_outside_triplets == 1: + if self.order_of_last_zero_digit == len(self.integers_to_read[0]) - 1: # number like x and all 0s, read ordinal x 0..0 and return - if not (self.okunacak_uclu_grup_sayisi == 2 and self.okunacak_tam_sayi[0][0] == "1"): - oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] - oku += self.ORDINAL_UCLU_GRUPLAR[self.okunacak_uclu_grup_sayisi - 1] + if not (self.total_triplets_to_read == 2 and self.integers_to_read[0][0] == "1"): + oku += self.CARDINAL_ONES[int(self.integers_to_read[0][0])] + oku += self.ORDINAL_TRIPLETS[self.total_triplets_to_read - 1] return oku - if self.son_sifir_basamagi < len(self.okunacak_tam_sayi[0]) - 1: + if self.order_of_last_zero_digit < len(self.integers_to_read[0]) - 1: # number like x and others, read cardinal x n..n and return - if not (self.okunacak_uclu_grup_sayisi == 2 and self.okunacak_tam_sayi[0][0] == "1"): - oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] - oku += self.CARDINAL_UCLU_GRUPLAR[self.okunacak_uclu_grup_sayisi - 1] + if not (self.total_triplets_to_read == 2 and self.integers_to_read[0][0] == "1"): + oku += self.CARDINAL_ONES[int(self.integers_to_read[0][0])] + oku += self.CARDINAL_TRIPLETS[self.total_triplets_to_read - 1] - if self.okunacak_artik_basamak_sayisi == 0: - if self.son_sifir_basamagi == len(self.okunacak_tam_sayi[0]) - 1: + if self.total_digits_outside_triplets == 0: + if self.order_of_last_zero_digit == len(self.integers_to_read[0]) - 1: # number like x00 and all 0s, read ordinal x00 0..0 and return - if not self.okunacak_tam_sayi[0][0] == "1": - oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] - oku += self.CARDINAL_YUZLER[0] - oku += self.ORDINAL_UCLU_GRUPLAR[self.okunacak_uclu_grup_sayisi - 1] + if not self.integers_to_read[0][0] == "1": + oku += self.CARDINAL_ONES[int(self.integers_to_read[0][0])] + oku += self.CARDINAL_HUNDREDS[0] + oku += self.ORDINAL_TRIPLETS[self.total_triplets_to_read - 1] return oku - if self.son_sifir_basamagi == len(self.okunacak_tam_sayi[0]) - 2: + if self.order_of_last_zero_digit == len(self.integers_to_read[0]) - 2: # number like xy0 and all 0s, read ordinal xy0 0..0 and return - if not self.okunacak_tam_sayi[0][0] == "1": - oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] - oku += self.CARDINAL_YUZLER[0] - oku += self.CARDINAL_ONLAR[int(self.okunacak_tam_sayi[0][1])] - oku += self.ORDINAL_UCLU_GRUPLAR[self.okunacak_uclu_grup_sayisi - 1] + if not self.integers_to_read[0][0] == "1": + oku += self.CARDINAL_ONES[int(self.integers_to_read[0][0])] + oku += self.CARDINAL_HUNDREDS[0] + oku += self.CARDINAL_TEN[int(self.integers_to_read[0][1])] + oku += self.ORDINAL_TRIPLETS[self.total_triplets_to_read - 1] return oku - if self.son_sifir_basamagi == len(self.okunacak_tam_sayi[0]) - 3: + if self.order_of_last_zero_digit == len(self.integers_to_read[0]) - 3: # number like xyz and all 0s, read ordinal xyz 0..0 and return - if not self.okunacak_tam_sayi[0][0] == "1": - oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] - oku += self.CARDINAL_YUZLER[0] - oku += self.CARDINAL_ONLAR[int(self.okunacak_tam_sayi[0][1])] - if not self.okunacak_tam_sayi[0][2] == "0": - oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][2])] - oku += self.ORDINAL_UCLU_GRUPLAR[self.okunacak_uclu_grup_sayisi - 1] + if not self.integers_to_read[0][0] == "1": + oku += self.CARDINAL_ONES[int(self.integers_to_read[0][0])] + oku += self.CARDINAL_HUNDREDS[0] + oku += self.CARDINAL_TEN[int(self.integers_to_read[0][1])] + if not self.integers_to_read[0][2] == "0": + oku += self.CARDINAL_ONES[int(self.integers_to_read[0][2])] + oku += self.ORDINAL_TRIPLETS[self.total_triplets_to_read - 1] return oku - if self.son_sifir_basamagi < len(self.okunacak_tam_sayi[0]) - 3: + if self.order_of_last_zero_digit < len(self.integers_to_read[0]) - 3: # number like xyz and all others, read cardinal xyz n..n - if not self.okunacak_tam_sayi[0][0] == "1": - oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][0])] - oku += self.CARDINAL_YUZLER[0] - oku += self.CARDINAL_ONLAR[int(self.okunacak_tam_sayi[0][1])] - if not self.okunacak_tam_sayi[0][2] == "0": - if not (self.okunacak_uclu_grup_sayisi == 2 and self.okunacak_tam_sayi[0][2] == "1"): - oku += self.CARDINAL_BIRLER[int(self.okunacak_tam_sayi[0][2])] - oku += self.CARDINAL_UCLU_GRUPLAR[self.okunacak_uclu_grup_sayisi - 1] + if not self.integers_to_read[0][0] == "1": + oku += self.CARDINAL_ONES[int(self.integers_to_read[0][0])] + oku += self.CARDINAL_HUNDREDS[0] + oku += self.CARDINAL_TEN[int(self.integers_to_read[0][1])] + if not self.integers_to_read[0][2] == "0": + if not (self.total_triplets_to_read == 2 and self.integers_to_read[0][2] == "1"): + oku += self.CARDINAL_ONES[int(self.integers_to_read[0][2])] + oku += self.CARDINAL_TRIPLETS[self.total_triplets_to_read - 1] - for i in list(range(self.okunacak_uclu_grup_sayisi - 1, 0, -1)): - okunan_grup_sirasi = self.okunacak_uclu_grup_sayisi - i - if self.okunacak_artik_basamak_sayisi == 0: + for i in list(range(self.total_triplets_to_read - 1, 0, -1)): + okunan_grup_sirasi = self.total_triplets_to_read - i + if self.total_digits_outside_triplets == 0: son_okunan_basamak_sirasi = okunan_grup_sirasi * 3 else: - son_okunan_basamak_sirasi = (okunan_grup_sirasi - 1) * 3 + self.okunacak_artik_basamak_sayisi + son_okunan_basamak_sirasi = (okunan_grup_sirasi - 1) * 3 + self.total_digits_outside_triplets - if not self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi: son_okunan_basamak_sirasi + 3] == "000": - if not self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi] == "0": - if not self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi] == "1": - oku += self.CARDINAL_BIRLER[ - int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi])] - if self.son_sifir_basamagi == len(self.okunacak_tam_sayi[0]) - ( + if not self.integers_to_read[0][son_okunan_basamak_sirasi: son_okunan_basamak_sirasi + 3] == "000": + if not self.integers_to_read[0][son_okunan_basamak_sirasi] == "0": + if not self.integers_to_read[0][son_okunan_basamak_sirasi] == "1": + oku += self.CARDINAL_ONES[ + int(self.integers_to_read[0][son_okunan_basamak_sirasi])] + if self.order_of_last_zero_digit == len(self.integers_to_read[0]) - ( son_okunan_basamak_sirasi) - 1: if i == 1: - oku += self.ORDINAL_YUZLER[0] + oku += self.ORDINAL_HUNDREDS[0] return oku elif i > 1: - oku += self.CARDINAL_YUZLER[0] - oku += self.ORDINAL_UCLU_GRUPLAR[i - 1] + oku += self.CARDINAL_HUNDREDS[0] + oku += self.ORDINAL_TRIPLETS[i - 1] return oku else: - oku += self.CARDINAL_YUZLER[0] + oku += self.CARDINAL_HUNDREDS[0] - if not self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 1] == "0": - if self.son_sifir_basamagi == len(self.okunacak_tam_sayi[0]) - ( + if not self.integers_to_read[0][son_okunan_basamak_sirasi + 1] == "0": + if self.order_of_last_zero_digit == len(self.integers_to_read[0]) - ( son_okunan_basamak_sirasi) - 2: if i == 1: - oku += self.ORDINAL_ONLAR[ - int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 1])] + oku += self.ORDINAL_TENS[ + int(self.integers_to_read[0][son_okunan_basamak_sirasi + 1])] return oku elif i > 1: - oku += self.CARDINAL_ONLAR[ - int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 1])] - oku += self.ORDINAL_UCLU_GRUPLAR[i - 1] + oku += self.CARDINAL_TEN[ + int(self.integers_to_read[0][son_okunan_basamak_sirasi + 1])] + oku += self.ORDINAL_TRIPLETS[i - 1] return oku else: - oku += self.CARDINAL_ONLAR[ - int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 1])] + oku += self.CARDINAL_TEN[ + int(self.integers_to_read[0][son_okunan_basamak_sirasi + 1])] - if not self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2] == "0": - if self.son_sifir_basamagi == len(self.okunacak_tam_sayi[0]) - ( + if not self.integers_to_read[0][son_okunan_basamak_sirasi + 2] == "0": + if self.order_of_last_zero_digit == len(self.integers_to_read[0]) - ( son_okunan_basamak_sirasi) - 3: if i == 1: - oku += self.ORDINAL_BIRLER[ - int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2])] + oku += self.ORDINAL_ONES[ + int(self.integers_to_read[0][son_okunan_basamak_sirasi + 2])] return oku if i == 2: - if not self.okunacak_tam_sayi[0][ + if not self.integers_to_read[0][ son_okunan_basamak_sirasi: son_okunan_basamak_sirasi + 2] == "00": - oku += self.CARDINAL_BIRLER[ - int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2])] - elif not self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2] == "1": - oku += self.CARDINAL_BIRLER[ - int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2])] - oku += self.ORDINAL_UCLU_GRUPLAR[i - 1] + oku += self.CARDINAL_ONES[ + int(self.integers_to_read[0][son_okunan_basamak_sirasi + 2])] + elif not self.integers_to_read[0][son_okunan_basamak_sirasi + 2] == "1": + oku += self.CARDINAL_ONES[ + int(self.integers_to_read[0][son_okunan_basamak_sirasi + 2])] + oku += self.ORDINAL_TRIPLETS[i - 1] return oku if i > 2: - oku += self.CARDINAL_BIRLER[ - int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2])] - oku += self.ORDINAL_UCLU_GRUPLAR[i - 1] + oku += self.CARDINAL_ONES[ + int(self.integers_to_read[0][son_okunan_basamak_sirasi + 2])] + oku += self.ORDINAL_TRIPLETS[i - 1] return oku else: - if not self.okunacak_tam_sayi[0][ + if not self.integers_to_read[0][ son_okunan_basamak_sirasi: son_okunan_basamak_sirasi + 2] == "00": - oku += self.CARDINAL_BIRLER[ - int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2])] + oku += self.CARDINAL_ONES[ + int(self.integers_to_read[0][son_okunan_basamak_sirasi + 2])] else: - if not self.okunacak_tam_sayi[0][ + if not self.integers_to_read[0][ son_okunan_basamak_sirasi: son_okunan_basamak_sirasi + 2] == "00": - oku += self.CARDINAL_BIRLER[ - int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2])] - elif not self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2] == "1": - oku += self.CARDINAL_BIRLER[ - int(self.okunacak_tam_sayi[0][son_okunan_basamak_sirasi + 2])] + oku += self.CARDINAL_ONES[ + int(self.integers_to_read[0][son_okunan_basamak_sirasi + 2])] + elif not self.integers_to_read[0][son_okunan_basamak_sirasi + 2] == "1": + oku += self.CARDINAL_ONES[ + int(self.integers_to_read[0][son_okunan_basamak_sirasi + 2])] - oku += self.CARDINAL_UCLU_GRUPLAR[i - 1] + oku += self.CARDINAL_TRIPLETS[i - 1] return oku @@ -538,27 +534,27 @@ class Num2Word_TR(object): isordinal = self.verify_ordinal(value) if isordinal: self.splitnum(value) - oku = self.okunacak_tam_sayi[0] + self.ORDINAL_SIGN[0] + oku = self.integers_to_read[0] + self.ORDINAL_SIGN[0] return oku # def inflect(self, value, text): def to_splitnum(self, val, hightxt="", lowtxt="", jointxt="", divisor=100, longval=True, cents=True): - kesirlibolum = str(int(val * 10**self.precision)) - self.okunacak_tam_sayi = [str(int(val)), kesirlibolum[len(kesirlibolum)-self.precision:]] - if len(self.okunacak_tam_sayi[0]) % 3 > 0: - self.okunacak_uclu_grup_sayisi = (len(self.okunacak_tam_sayi[0]) // 3) + 1 - elif len(self.okunacak_tam_sayi[0]) % 3 == 0: - self.okunacak_uclu_grup_sayisi = len(self.okunacak_tam_sayi[0]) // 3 - self.okunacak_artik_basamak_sayisi = len(self.okunacak_tam_sayi[0]) % 3 + kesirlibolum = str(int(val * 10 ** self.precision)) + self.integers_to_read = [str(int(val)), kesirlibolum[len(kesirlibolum) - self.precision:]] + if len(self.integers_to_read[0]) % 3 > 0: + self.total_triplets_to_read = (len(self.integers_to_read[0]) // 3) + 1 + elif len(self.integers_to_read[0]) % 3 == 0: + self.total_triplets_to_read = len(self.integers_to_read[0]) // 3 + self.total_digits_outside_triplets = len(self.integers_to_read[0]) % 3 - okunacak = list(self.okunacak_tam_sayi[0][::-1]) - self.son_sifir_basamagi = 0 + okunacak = list(self.integers_to_read[0][::-1]) + self.order_of_last_zero_digit = 0 found = 0 for i in range(len(okunacak) - 1): if int(okunacak[i]) == 0 and found == 0: - self.son_sifir_basamagi = i + 1 + self.order_of_last_zero_digit = i + 1 else: found = 1 @@ -566,10 +562,14 @@ class Num2Word_TR(object): return self.to_cardinal(value) def to_currency(self, value, **kwargs): - return self.to_cardinal(value) + valueparts = self.to_cardinal(value).split(self.pointword) + if len(valueparts) == 1: + return valueparts[0] + self.CURRENCY_UNIT[0] + if len(valueparts) == 2: + return self.CURRENCY_UNIT[0].join(valueparts) + self.CURRENCY_SUBUNIT[0] - # def base_setup(self): + # def base_setup(self): - # def setup(self): + # def setup(self): - # def test(self, value): + # def test(self, value): From a235058ba6a89f1d5a865885dd7721234c7c1147 Mon Sep 17 00:00:00 2001 From: Tufan Kaynak <31142607+toofun666@users.noreply.github.com> Date: Sat, 2 Sep 2017 14:22:50 +0300 Subject: [PATCH 70/99] refactoring data elements --- num2words/lang_TR.py | 587 +++++++++++++++++++++++-------------------- tests/test_tr.py | 16 ++ 2 files changed, 326 insertions(+), 277 deletions(-) diff --git a/num2words/lang_TR.py b/num2words/lang_TR.py index 45add35..fe51b00 100644 --- a/num2words/lang_TR.py +++ b/num2words/lang_TR.py @@ -34,25 +34,84 @@ class Num2Word_TR(object): self.errmsg_negord = u"Pozitif olmayan {} sıralamada kullanılamaz." # abs(%s) must be less than %s. self.errmsg_toobig = u"abs({}) sayı yazıya çevirmek için çok büyük. Yazıya çevrilebilecek en büyük rakam {}." - self.exclude_title = ["et", "virgule", "moins"] + self.exclude_title = [] # ordered number tuples in Turkish - self.ORDINAL_SIGN = (",",) - self.CARDINAL_ONES = ( - u"sıfır", u"bir", u"iki", u"üç", u"dört", u"beş", u"altı", u"yedi", u"sekiz", u"dokuz",) - self.ORDINAL_ONES = ( - u"", u"birinci", u"ikinci", u"üçüncü", u"dördüncü", u"beşinci", u"altıncı", u"yedinci", u"sekizinci", - u"dokuzuncu",) - self.CARDINAL_TEN = ( - u"", u"on", u"yirmi", u"otuz", u"kırk", u"elli", u"altmış", u"yetmiş", u"seksen", u"doksan",) - self.ORDINAL_TENS = ( - u"", u"onuncu", u"yirminci", u"otuzuncu", u"kırkıncı", u"ellinci", u"altmışıncı", u"yetmişinci", - u"sekseninci", u"doksanıncı",) - self.CARDINAL_HUNDREDS = (u"yüz",) - self.ORDINAL_HUNDREDS = (u"yüzüncü",) - self.CARDINAL_TRIPLETS = (u"", u"bin", u"milyon", u"milyar", u"trilyon", u"katrilyon", u"kentilyon",) - self.ORDINAL_TRIPLETS = ( - u"", u"bininci", u"milyonuncu", u"milyarıncı", u"trilyonuncu", u"katrilyonuncu", u"kentilyon",) - self.MAXVAL = (10 ** (len(self.CARDINAL_TRIPLETS) * 3)) - 1 + self.DECIMAL_SIGN = (",",) + self.ORDINAL_SIGN = (".",) + self.ZERO = (u"sıfır",) + self.CARDINAL_ONES = { + "1": u"bir", + "2": u"iki", + "3": u"üç", + "4": u"dört", + "5": u"beş", + "6": u"altı", + "7": u"yedi", + "8": u"sekiz", + "9": u"dokuz" + } + self.ORDINAL_ONES = { + "1": u"birinci", + "2": u"ikinci", + "3": u"üçüncü", + "4": u"dördüncü", + "5": u"beşinci", + "6": u"altıncı", + "7": u"yedinci", + "8": u"sekizinci", + "9": u"dokuzuncu", + } + self.CARDINAL_TENS = { + "1": u"on", + "2": u"yirmi", + "3": u"otuz", + "4": u"kırk", + "5": u"elli", + "6": u"altmış", + "7": u"yetmiş", + "8": u"seksen", + "9": u"doksan" + } + self.ORDINAL_TENS = { + "1": u"onuncu", + "2": u"yirminci", + "3": u"otuzuncu", + "4": u"kırkıncı", + "5": u"ellinci", + "6": u"altmışıncı", + "7": u"yetmişinci", + "8": u"sekseninci", + "9": u"doksanıncı" + } + self.HUNDREDS = { + "2": u"iki", + "3": u"üç", + "4": u"dört", + "5": u"beş", + "6": u"altı", + "7": u"yedi", + "8": u"sekiz", + "9": u"dokuz" + } + self.CARDINAL_HUNDRED = (u"yüz",) + self.ORDINAL_HUNDRED = (u"yüzüncü",) + self.CARDINAL_TRIPLETS = { + 1: u"bin", + 2: u"milyon", + 3: u"milyar", + 4: u"trilyon", + 5: u"katrilyon", + 6: u"kentilyon" + } + self.ORDINAL_TRIPLETS = { + 1: u"bininci", + 2: u"milyonuncu", + 3: u"milyarıncı", + 4: u"trilyonuncu", + 5: u"katrilyonuncu", + 6: u"kentilyon" + } + self.MAXVAL = (10 ** ((len(self.CARDINAL_TRIPLETS) + 1) * 3)) - 1 self.integers_to_read = [] self.total_triplets_to_read = 0 @@ -71,7 +130,7 @@ class Num2Word_TR(object): return self.to_splitnum(value) def to_cardinal(self, value): - oku = "" + wrd = "" is_cardinal = self.verify_cardinal(value) if is_cardinal: if not int(value) == value: @@ -80,215 +139,203 @@ class Num2Word_TR(object): if self.order_of_last_zero_digit >= len(self.integers_to_read[0]): # number like 00 and all 0s and even more, raise error - return oku + return wrd if self.total_triplets_to_read == 1: if self.total_digits_outside_triplets == 2: if self.order_of_last_zero_digit == 1: # number like x0, read cardinal x0 and return - oku += self.CARDINAL_TEN[int(self.integers_to_read[0][0])] - return oku + wrd += self.CARDINAL_TENS.get(self.integers_to_read[0][0], "") + return wrd if self.order_of_last_zero_digit == 0: # number like xy, read cardinal xy and return - oku += self.CARDINAL_TEN[int(self.integers_to_read[0][0])] - if not self.integers_to_read[0][0] == "0": - oku += self.CARDINAL_ONES[int(self.integers_to_read[0][1])] - return oku + wrd += self.CARDINAL_TENS.get(self.integers_to_read[0][0], "") + wrd += self.CARDINAL_ONES.get(self.integers_to_read[0][1], "") + return wrd if self.total_digits_outside_triplets == 1: if self.order_of_last_zero_digit == 0: # number like x, read ordinal x and return - oku += self.CARDINAL_ONES[int(self.integers_to_read[0][0])] - return oku + wrd += self.CARDINAL_ONES.get(self.integers_to_read[0][0], "") + return wrd if self.total_digits_outside_triplets == 0: if self.order_of_last_zero_digit == 2: # number like x00, read cardinal x00 and return - if not self.integers_to_read[0][0] == "1": - oku += self.CARDINAL_ONES[int(self.integers_to_read[0][0])] - oku += self.CARDINAL_HUNDREDS[0] - return oku + wrd += self.HUNDREDS.get(self.integers_to_read[0][0], "") + wrd += self.CARDINAL_HUNDRED[0] + return wrd if self.order_of_last_zero_digit == 1: # number like xy0, read cardinal xy0 and return - if not self.integers_to_read[0][0] == "1": - oku += self.CARDINAL_ONES[int(self.integers_to_read[0][0])] - oku += self.CARDINAL_HUNDREDS[0] - oku += self.CARDINAL_TEN[int(self.integers_to_read[0][1])] - return oku + wrd += self.HUNDREDS.get(self.integers_to_read[0][0], "") + wrd += self.CARDINAL_HUNDRED[0] + wrd += self.CARDINAL_TENS.get(self.integers_to_read[0][1], "") + return wrd if self.order_of_last_zero_digit == 0: # number like xyz, read cardinal xyz and return - if not self.integers_to_read[0][0] == "1": - oku += self.CARDINAL_ONES[int(self.integers_to_read[0][0])] - oku += self.CARDINAL_HUNDREDS[0] - oku += self.CARDINAL_TEN[int(self.integers_to_read[0][1])] - if not self.integers_to_read[0][2] == "0": - oku += self.CARDINAL_ONES[int(self.integers_to_read[0][2])] - return oku + wrd += self.HUNDREDS.get(self.integers_to_read[0][0], "") + wrd += self.CARDINAL_HUNDRED[0] + wrd += self.CARDINAL_TENS.get(self.integers_to_read[0][1], "") + wrd += self.CARDINAL_ONES.get(self.integers_to_read[0][2], "") + return wrd if self.total_triplets_to_read >= 2: if self.total_digits_outside_triplets == 2: if self.order_of_last_zero_digit == len(self.integers_to_read[0]) - 1: # number like x0 and all 0s, read cardinal x0 0..0 and return - oku += self.CARDINAL_TEN[int(self.integers_to_read[0][0])] - oku += self.CARDINAL_TRIPLETS[self.total_triplets_to_read - 1] - return oku + wrd += self.CARDINAL_TENS.get(self.integers_to_read[0][0], "") + wrd += self.CARDINAL_TRIPLETS[self.total_triplets_to_read - 1] + return wrd if self.order_of_last_zero_digit == len(self.integers_to_read[0]) - 2: # number like xy and all 0s, read cardinal xy 0..0 and return - oku += self.CARDINAL_TEN[int(self.integers_to_read[0][0])] - if not self.integers_to_read[0][1] == "0": - oku += self.CARDINAL_ONES[int(self.integers_to_read[0][1])] - oku += self.CARDINAL_TRIPLETS[self.total_triplets_to_read - 1] - return oku + wrd += self.CARDINAL_TENS.get(self.integers_to_read[0][0], "") + wrd += self.CARDINAL_ONES.get(self.integers_to_read[0][1], "") + wrd += self.CARDINAL_TRIPLETS[self.total_triplets_to_read - 1] + return wrd if self.order_of_last_zero_digit < len(self.integers_to_read[0]) - 2: # number like xy and others, read cardinal xy n..n and return - oku += self.CARDINAL_TEN[int(self.integers_to_read[0][0])] - if not self.integers_to_read[0][1] == "0": - oku += self.CARDINAL_ONES[int(self.integers_to_read[0][1])] - oku += self.CARDINAL_TRIPLETS[self.total_triplets_to_read - 1] + wrd += self.CARDINAL_TENS.get(self.integers_to_read[0][0], "") + wrd += self.CARDINAL_ONES.get(self.integers_to_read[0][1], "") + wrd += self.CARDINAL_TRIPLETS[self.total_triplets_to_read - 1] if self.total_digits_outside_triplets == 1: if self.order_of_last_zero_digit == len(self.integers_to_read[0]) - 1: # number like x and all 0s, read cardinal x 0..0 and return if not (self.total_triplets_to_read == 2 and self.integers_to_read[0][0] == "1"): - oku += self.CARDINAL_ONES[int(self.integers_to_read[0][0])] - oku += self.CARDINAL_TRIPLETS[self.total_triplets_to_read - 1] - return oku + wrd += self.CARDINAL_ONES.get(self.integers_to_read[0][0], "") + wrd += self.CARDINAL_TRIPLETS[self.total_triplets_to_read - 1] + return wrd if self.order_of_last_zero_digit < len(self.integers_to_read[0]) - 1: # number like x and others, read cardinal x n..n and return if not (self.total_triplets_to_read == 2 and self.integers_to_read[0][0] == "1"): - oku += self.CARDINAL_ONES[int(self.integers_to_read[0][0])] - oku += self.CARDINAL_TRIPLETS[self.total_triplets_to_read - 1] + wrd += self.CARDINAL_ONES.get(self.integers_to_read[0][0], "") + wrd += self.CARDINAL_TRIPLETS[self.total_triplets_to_read - 1] if self.total_digits_outside_triplets == 0: if self.order_of_last_zero_digit == len(self.integers_to_read[0]) - 1: # number like x00 and all 0s, read cardinal x00 0..0 and return - if not self.integers_to_read[0][0] == "1": - oku += self.CARDINAL_ONES[int(self.integers_to_read[0][0])] - oku += self.CARDINAL_HUNDREDS[0] - oku += self.CARDINAL_TRIPLETS[self.total_triplets_to_read - 1] - return oku + wrd += self.HUNDREDS.get(self.integers_to_read[0][0], "") + wrd += self.CARDINAL_HUNDRED[0] + wrd += self.CARDINAL_TRIPLETS[self.total_triplets_to_read - 1] + return wrd if self.order_of_last_zero_digit == len(self.integers_to_read[0]) - 2: # number like xy0 and all 0s, read cardinal xy0 0..0 and return - if not self.integers_to_read[0][0] == "1": - oku += self.CARDINAL_ONES[int(self.integers_to_read[0][0])] - oku += self.CARDINAL_HUNDREDS[0] - oku += self.CARDINAL_TEN[int(self.integers_to_read[0][1])] - oku += self.CARDINAL_TRIPLETS[self.total_triplets_to_read - 1] - return oku + wrd += self.HUNDREDS.get(self.integers_to_read[0][0], "") + wrd += self.CARDINAL_HUNDRED[0] + wrd += self.CARDINAL_TENS.get(self.integers_to_read[0][1], "") + wrd += self.CARDINAL_TRIPLETS[self.total_triplets_to_read - 1] + return wrd if self.order_of_last_zero_digit == len(self.integers_to_read[0]) - 3: # number like xyz and all 0s, read cardinal xyz 0..0 and return - if not self.integers_to_read[0][0] == "1": - oku += self.CARDINAL_ONES[int(self.integers_to_read[0][0])] - oku += self.CARDINAL_HUNDREDS[0] - oku += self.CARDINAL_TEN[int(self.integers_to_read[0][1])] - if not self.integers_to_read[0][2] == "0": - oku += self.CARDINAL_ONES[int(self.integers_to_read[0][2])] - oku += self.CARDINAL_TRIPLETS[self.total_triplets_to_read - 1] - return oku + wrd += self.HUNDREDS.get(self.integers_to_read[0][0], "") + wrd += self.CARDINAL_HUNDRED[0] + wrd += self.CARDINAL_TENS.get(self.integers_to_read[0][1], "") + wrd += self.CARDINAL_ONES.get(self.integers_to_read[0][2], "") + wrd += self.CARDINAL_TRIPLETS[self.total_triplets_to_read - 1] + return wrd if self.order_of_last_zero_digit < len(self.integers_to_read[0]) - 3: # number like xyz and all others, read cardinal xyz n..n - if not self.integers_to_read[0][0] == "1": - oku += self.CARDINAL_ONES[int(self.integers_to_read[0][0])] - oku += self.CARDINAL_HUNDREDS[0] - oku += self.CARDINAL_TEN[int(self.integers_to_read[0][1])] - if not self.integers_to_read[0][2] == "0": - if not (self.total_triplets_to_read == 2 and self.integers_to_read[0][2] == "1"): - oku += self.CARDINAL_ONES[int(self.integers_to_read[0][2])] - oku += self.CARDINAL_TRIPLETS[self.total_triplets_to_read - 1] + wrd += self.HUNDREDS.get(self.integers_to_read[0][0], "") + wrd += self.CARDINAL_HUNDRED[0] + wrd += self.CARDINAL_TENS.get(self.integers_to_read[0][1], "") + if not (self.total_triplets_to_read == 2 and self.integers_to_read[0][2] == "1"): + wrd += self.CARDINAL_ONES.get(self.integers_to_read[0][2], "") + wrd += self.CARDINAL_TRIPLETS[self.total_triplets_to_read - 1] for i in list(range(self.total_triplets_to_read - 1, 0, -1)): - okunan_grup_sirasi = self.total_triplets_to_read - i + reading_triplet_order = self.total_triplets_to_read - i if self.total_digits_outside_triplets == 0: - son_okunan_basamak_sirasi = okunan_grup_sirasi * 3 + last_read_digit_order = reading_triplet_order * 3 else: - son_okunan_basamak_sirasi = (okunan_grup_sirasi - 1) * 3 + self.total_digits_outside_triplets + last_read_digit_order = (reading_triplet_order - 1) * 3 + self.total_digits_outside_triplets - if not self.integers_to_read[0][son_okunan_basamak_sirasi: son_okunan_basamak_sirasi + 3] == "000": - if not self.integers_to_read[0][son_okunan_basamak_sirasi] == "0": - if not self.integers_to_read[0][son_okunan_basamak_sirasi] == "1": - oku += self.CARDINAL_ONES[ - int(self.integers_to_read[0][son_okunan_basamak_sirasi])] + if not self.integers_to_read[0][last_read_digit_order: last_read_digit_order + 3] == "000": + if not self.integers_to_read[0][last_read_digit_order] == "0": + wrd += self.HUNDREDS.get(self.integers_to_read[0][last_read_digit_order], "") if self.order_of_last_zero_digit == len(self.integers_to_read[0]) - ( - son_okunan_basamak_sirasi) - 1: + last_read_digit_order) - 1: if i == 1: - oku += self.CARDINAL_HUNDREDS[0] - return oku + wrd += self.CARDINAL_HUNDRED[0] + return wrd elif i > 1: - oku += self.CARDINAL_HUNDREDS[0] - oku += self.CARDINAL_TRIPLETS[i - 1] - return oku + wrd += self.CARDINAL_HUNDRED[0] + wrd += self.CARDINAL_TRIPLETS[i - 1] + return wrd else: - oku += self.CARDINAL_HUNDREDS[0] + wrd += self.CARDINAL_HUNDRED[0] - if not self.integers_to_read[0][son_okunan_basamak_sirasi + 1] == "0": + if not self.integers_to_read[0][last_read_digit_order + 1] == "0": if self.order_of_last_zero_digit == len(self.integers_to_read[0]) - ( - son_okunan_basamak_sirasi) - 2: + last_read_digit_order) - 2: if i == 1: - oku += self.CARDINAL_TEN[ - int(self.integers_to_read[0][son_okunan_basamak_sirasi + 1])] - return oku + wrd += self.CARDINAL_TENS.get( + self.integers_to_read[0][last_read_digit_order + 1], "") + return wrd elif i > 1: - oku += self.CARDINAL_TEN[ - int(self.integers_to_read[0][son_okunan_basamak_sirasi + 1])] - oku += self.CARDINAL_TRIPLETS[i - 1] - return oku + wrd += self.CARDINAL_TENS.get( + self.integers_to_read[0][last_read_digit_order + 1], "") + wrd += self.CARDINAL_TRIPLETS[i - 1] + return wrd else: - oku += self.CARDINAL_TEN[ - int(self.integers_to_read[0][son_okunan_basamak_sirasi + 1])] + wrd += self.CARDINAL_TENS.get(self.integers_to_read[0][last_read_digit_order + 1], + "") - if not self.integers_to_read[0][son_okunan_basamak_sirasi + 2] == "0": + if not self.integers_to_read[0][last_read_digit_order + 2] == "0": if self.order_of_last_zero_digit == len(self.integers_to_read[0]) - ( - son_okunan_basamak_sirasi) - 3: + last_read_digit_order) - 3: if i == 1: - oku += self.CARDINAL_ONES[ - int(self.integers_to_read[0][son_okunan_basamak_sirasi + 2])] - return oku + wrd += self.CARDINAL_ONES.get( + self.integers_to_read[0][last_read_digit_order + 2], "") + return wrd if i == 2: if not self.integers_to_read[0][ - son_okunan_basamak_sirasi: son_okunan_basamak_sirasi + 2] == "00": - oku += self.CARDINAL_ONES[ - int(self.integers_to_read[0][son_okunan_basamak_sirasi + 2])] - elif not self.integers_to_read[0][son_okunan_basamak_sirasi + 2] == "1": - oku += self.CARDINAL_ONES[ - int(self.integers_to_read[0][son_okunan_basamak_sirasi + 2])] - oku += self.CARDINAL_TRIPLETS[i - 1] - return oku + last_read_digit_order: last_read_digit_order + 2] == "00": + wrd += self.CARDINAL_ONES.get( + self.integers_to_read[0][last_read_digit_order + 2], "") + elif not self.integers_to_read[0][last_read_digit_order + 2] == "1": + wrd += self.CARDINAL_ONES.get( + self.integers_to_read[0][last_read_digit_order + 2], "") + wrd += self.CARDINAL_TRIPLETS[i - 1] + return wrd if i > 2: - oku += self.CARDINAL_ONES[ - int(self.integers_to_read[0][son_okunan_basamak_sirasi + 2])] - oku += self.CARDINAL_TRIPLETS[i - 1] - return oku + wrd += self.CARDINAL_ONES.get( + self.integers_to_read[0][last_read_digit_order + 2], "") + wrd += self.CARDINAL_TRIPLETS[i - 1] + return wrd else: if not self.integers_to_read[0][ - son_okunan_basamak_sirasi: son_okunan_basamak_sirasi + 2] == "00": - oku += self.CARDINAL_ONES[ - int(self.integers_to_read[0][son_okunan_basamak_sirasi + 2])] + last_read_digit_order: last_read_digit_order + 2] == "00": + wrd += self.CARDINAL_ONES.get( + self.integers_to_read[0][last_read_digit_order + 2], "") else: if i == 2: if not self.integers_to_read[0][ - son_okunan_basamak_sirasi: son_okunan_basamak_sirasi + 2] == "00": - oku += self.CARDINAL_ONES[ - int(self.integers_to_read[0][son_okunan_basamak_sirasi + 2])] - elif not self.integers_to_read[0][son_okunan_basamak_sirasi + 2] == "1": - oku += self.CARDINAL_ONES[ - int(self.integers_to_read[0][son_okunan_basamak_sirasi + 2])] + last_read_digit_order: last_read_digit_order + 2] == "00": + wrd += self.CARDINAL_ONES.get( + self.integers_to_read[0][last_read_digit_order + 2], "") + elif not self.integers_to_read[0][last_read_digit_order + 2] == "1": + wrd += self.CARDINAL_ONES.get( + self.integers_to_read[0][last_read_digit_order + 2], "") - oku += self.CARDINAL_TRIPLETS[i - 1] + wrd += self.CARDINAL_TRIPLETS[i - 1] - return oku + return wrd def to_cardinal_float(self, value): self.splitnum(value) - oku = "" - oku += self.pointword + wrd = "" + wrd += self.pointword if len(self.integers_to_read[1]) >= 1: - if not self.integers_to_read[1][0] == "0": - oku += self.CARDINAL_TEN[int(self.integers_to_read[1][0])] + wrd += self.CARDINAL_TENS.get(self.integers_to_read[1][0], "") + if len(self.integers_to_read[1]) == 2: - if not self.integers_to_read[1][1] == "0": - oku += self.CARDINAL_ONES[int(self.integers_to_read[1][1])] - oku = self.to_cardinal(int(self.integers_to_read[0])) + oku - return oku + wrd += self.CARDINAL_ONES.get(self.integers_to_read[1][1], "") + + if self.integers_to_read[0] == "0": + wrd = self.ZERO[0] + wrd + else: + wrd = self.to_cardinal(int(self.integers_to_read[0])) + wrd + return wrd # def merge(self, curr, next): @@ -325,218 +372,204 @@ class Num2Word_TR(object): # def set_wordnums(self): def to_ordinal(self, value): - oku = "" + wrd = "" isordinal = self.verify_ordinal(value) if isordinal: self.splitnum(value) if self.order_of_last_zero_digit >= len(self.integers_to_read[0]): # number like 00 and all 0s and even more, raise error - return oku + return wrd if self.total_triplets_to_read == 1: if self.total_digits_outside_triplets == 2: if self.order_of_last_zero_digit == 1: # number like x0, read ordinal x0 and return - oku += self.ORDINAL_TENS[int(self.integers_to_read[0][0])] - return oku + wrd += self.ORDINAL_TENS.get(self.integers_to_read[0][0], "") + return wrd if self.order_of_last_zero_digit == 0: # number like xy, read ordinal xy and return - oku += self.CARDINAL_TEN[int(self.integers_to_read[0][0])] - if not self.integers_to_read[0][0] == "0": - oku += self.ORDINAL_ONES[int(self.integers_to_read[0][1])] - return oku + wrd += self.CARDINAL_TENS.get(self.integers_to_read[0][0], "") + wrd += self.ORDINAL_ONES.get(self.integers_to_read[0][1], "") + return wrd if self.total_digits_outside_triplets == 1: if self.order_of_last_zero_digit == 0: # number like x, read ordinal x and return - oku += self.ORDINAL_ONES[int(self.integers_to_read[0][0])] - return oku + wrd += self.ORDINAL_ONES.get(self.integers_to_read[0][0], "") + return wrd if self.total_digits_outside_triplets == 0: if self.order_of_last_zero_digit == 2: # number like x00, read ordinal x00 and return - if not self.integers_to_read[0][0] == "1": - oku += self.CARDINAL_ONES[int(self.integers_to_read[0][0])] - oku += self.ORDINAL_HUNDREDS[0] - return oku + wrd += self.HUNDREDS.get(self.integers_to_read[0][0], "") + wrd += self.ORDINAL_HUNDRED[0] + return wrd if self.order_of_last_zero_digit == 1: # number like xy0, read ordinal xy0 and return - if not self.integers_to_read[0][0] == "1": - oku += self.CARDINAL_ONES[int(self.integers_to_read[0][0])] - oku += self.CARDINAL_HUNDREDS[0] - oku += self.ORDINAL_TENS[int(self.integers_to_read[0][1])] - return oku + wrd += self.HUNDREDS.get(self.integers_to_read[0][0], "") + wrd += self.CARDINAL_HUNDRED[0] + wrd += self.ORDINAL_TENS.get(self.integers_to_read[0][1], "") + return wrd if self.order_of_last_zero_digit == 0: # number like xyz, read ordinal xyz and return - if not self.integers_to_read[0][0] == "1": - oku += self.CARDINAL_ONES[int(self.integers_to_read[0][0])] - oku += self.CARDINAL_HUNDREDS[0] - oku += self.CARDINAL_TEN[int(self.integers_to_read[0][1])] + wrd += self.HUNDREDS.get(self.integers_to_read[0][0], "") + wrd += self.CARDINAL_HUNDRED[0] + wrd += self.CARDINAL_TENS.get(self.integers_to_read[0][1], "") if not self.integers_to_read[0][2] == "0": - oku += self.ORDINAL_ONES[int(self.integers_to_read[0][2])] - return oku + wrd += self.ORDINAL_ONES.get(self.integers_to_read[0][2], "") + return wrd if self.total_triplets_to_read >= 2: if self.total_digits_outside_triplets == 2: if self.order_of_last_zero_digit == len(self.integers_to_read[0]) - 1: # number like x0 and all 0s, read ordinal x0 0..0 and return - oku += self.CARDINAL_TEN[int(self.integers_to_read[0][0])] - oku += self.ORDINAL_TRIPLETS[self.total_triplets_to_read - 1] - return oku + wrd += self.CARDINAL_TENS.get(self.integers_to_read[0][0], "") + wrd += self.ORDINAL_TRIPLETS[self.total_triplets_to_read - 1] + return wrd if self.order_of_last_zero_digit == len(self.integers_to_read[0]) - 2: # number like xy and all 0s, read ordinal xy 0..0 and return - oku += self.CARDINAL_TEN[int(self.integers_to_read[0][0])] - if not self.integers_to_read[0][1] == "0": - oku += self.CARDINAL_ONES[int(self.integers_to_read[0][1])] - oku += self.ORDINAL_TRIPLETS[self.total_triplets_to_read - 1] - return oku + wrd += self.CARDINAL_TENS.get(self.integers_to_read[0][0], "") + wrd += self.CARDINAL_ONES.get(self.integers_to_read[0][1], "") + wrd += self.ORDINAL_TRIPLETS[self.total_triplets_to_read - 1] + return wrd if self.order_of_last_zero_digit < len(self.integers_to_read[0]) - 2: # number like xy and others, read cardinal xy n..n and return - oku += self.CARDINAL_TEN[int(self.integers_to_read[0][0])] - if not self.integers_to_read[0][1] == "0": - oku += self.CARDINAL_ONES[int(self.integers_to_read[0][1])] - - oku += self.CARDINAL_TRIPLETS[self.total_triplets_to_read - 1] + wrd += self.CARDINAL_TENS.get(self.integers_to_read[0][0], "") + wrd += self.CARDINAL_ONES.get(self.integers_to_read[0][1], "") + wrd += self.CARDINAL_TRIPLETS[self.total_triplets_to_read - 1] if self.total_digits_outside_triplets == 1: if self.order_of_last_zero_digit == len(self.integers_to_read[0]) - 1: # number like x and all 0s, read ordinal x 0..0 and return if not (self.total_triplets_to_read == 2 and self.integers_to_read[0][0] == "1"): - oku += self.CARDINAL_ONES[int(self.integers_to_read[0][0])] - oku += self.ORDINAL_TRIPLETS[self.total_triplets_to_read - 1] - return oku + wrd += self.CARDINAL_ONES.get(self.integers_to_read[0][0], "") + wrd += self.ORDINAL_TRIPLETS[self.total_triplets_to_read - 1] + return wrd if self.order_of_last_zero_digit < len(self.integers_to_read[0]) - 1: # number like x and others, read cardinal x n..n and return if not (self.total_triplets_to_read == 2 and self.integers_to_read[0][0] == "1"): - oku += self.CARDINAL_ONES[int(self.integers_to_read[0][0])] - oku += self.CARDINAL_TRIPLETS[self.total_triplets_to_read - 1] + wrd += self.CARDINAL_ONES.get(self.integers_to_read[0][0], "") + wrd += self.CARDINAL_TRIPLETS[self.total_triplets_to_read - 1] if self.total_digits_outside_triplets == 0: if self.order_of_last_zero_digit == len(self.integers_to_read[0]) - 1: # number like x00 and all 0s, read ordinal x00 0..0 and return - if not self.integers_to_read[0][0] == "1": - oku += self.CARDINAL_ONES[int(self.integers_to_read[0][0])] - oku += self.CARDINAL_HUNDREDS[0] - oku += self.ORDINAL_TRIPLETS[self.total_triplets_to_read - 1] - return oku + wrd += self.HUNDREDS.get(self.integers_to_read[0][0], "") + wrd += self.CARDINAL_HUNDRED[0] + wrd += self.ORDINAL_TRIPLETS[self.total_triplets_to_read - 1] + return wrd if self.order_of_last_zero_digit == len(self.integers_to_read[0]) - 2: # number like xy0 and all 0s, read ordinal xy0 0..0 and return - if not self.integers_to_read[0][0] == "1": - oku += self.CARDINAL_ONES[int(self.integers_to_read[0][0])] - oku += self.CARDINAL_HUNDREDS[0] - oku += self.CARDINAL_TEN[int(self.integers_to_read[0][1])] - oku += self.ORDINAL_TRIPLETS[self.total_triplets_to_read - 1] - return oku + wrd += self.HUNDREDS.get(self.integers_to_read[0][0], "") + wrd += self.CARDINAL_HUNDRED[0] + wrd += self.CARDINAL_TENS.get(self.integers_to_read[0][1], "") + wrd += self.ORDINAL_TRIPLETS[self.total_triplets_to_read - 1] + return wrd if self.order_of_last_zero_digit == len(self.integers_to_read[0]) - 3: # number like xyz and all 0s, read ordinal xyz 0..0 and return - if not self.integers_to_read[0][0] == "1": - oku += self.CARDINAL_ONES[int(self.integers_to_read[0][0])] - oku += self.CARDINAL_HUNDREDS[0] - oku += self.CARDINAL_TEN[int(self.integers_to_read[0][1])] - if not self.integers_to_read[0][2] == "0": - oku += self.CARDINAL_ONES[int(self.integers_to_read[0][2])] - oku += self.ORDINAL_TRIPLETS[self.total_triplets_to_read - 1] - return oku + wrd += self.HUNDREDS.get(self.integers_to_read[0][0], "") + wrd += self.CARDINAL_HUNDRED[0] + wrd += self.CARDINAL_TENS.get(self.integers_to_read[0][1], "") + wrd += self.CARDINAL_ONES.get(self.integers_to_read[0][2], "") + wrd += self.ORDINAL_TRIPLETS[self.total_triplets_to_read - 1] + return wrd if self.order_of_last_zero_digit < len(self.integers_to_read[0]) - 3: # number like xyz and all others, read cardinal xyz n..n - if not self.integers_to_read[0][0] == "1": - oku += self.CARDINAL_ONES[int(self.integers_to_read[0][0])] - oku += self.CARDINAL_HUNDREDS[0] - oku += self.CARDINAL_TEN[int(self.integers_to_read[0][1])] - if not self.integers_to_read[0][2] == "0": - if not (self.total_triplets_to_read == 2 and self.integers_to_read[0][2] == "1"): - oku += self.CARDINAL_ONES[int(self.integers_to_read[0][2])] - oku += self.CARDINAL_TRIPLETS[self.total_triplets_to_read - 1] + wrd += self.HUNDREDS.get(self.integers_to_read[0][0], "") + wrd += self.CARDINAL_HUNDRED[0] + wrd += self.CARDINAL_TENS.get(self.integers_to_read[0][1], "") + if not (self.total_triplets_to_read == 2 and self.integers_to_read[0][2] == "1"): + wrd += self.CARDINAL_ONES.get(self.integers_to_read[0][2], "") + wrd += self.CARDINAL_TRIPLETS[self.total_triplets_to_read - 1] for i in list(range(self.total_triplets_to_read - 1, 0, -1)): - okunan_grup_sirasi = self.total_triplets_to_read - i + reading_triplet_order = self.total_triplets_to_read - i if self.total_digits_outside_triplets == 0: - son_okunan_basamak_sirasi = okunan_grup_sirasi * 3 + last_read_digit_order = reading_triplet_order * 3 else: - son_okunan_basamak_sirasi = (okunan_grup_sirasi - 1) * 3 + self.total_digits_outside_triplets + last_read_digit_order = (reading_triplet_order - 1) * 3 + self.total_digits_outside_triplets - if not self.integers_to_read[0][son_okunan_basamak_sirasi: son_okunan_basamak_sirasi + 3] == "000": - if not self.integers_to_read[0][son_okunan_basamak_sirasi] == "0": - if not self.integers_to_read[0][son_okunan_basamak_sirasi] == "1": - oku += self.CARDINAL_ONES[ - int(self.integers_to_read[0][son_okunan_basamak_sirasi])] + if not self.integers_to_read[0][last_read_digit_order: last_read_digit_order + 3] == "000": + if not self.integers_to_read[0][last_read_digit_order] == "0": + if not self.integers_to_read[0][last_read_digit_order] == "1": + wrd += self.CARDINAL_ONES.get(self.integers_to_read[0][last_read_digit_order], "") if self.order_of_last_zero_digit == len(self.integers_to_read[0]) - ( - son_okunan_basamak_sirasi) - 1: + last_read_digit_order) - 1: if i == 1: - oku += self.ORDINAL_HUNDREDS[0] - return oku + wrd += self.ORDINAL_HUNDRED[0] + return wrd elif i > 1: - oku += self.CARDINAL_HUNDREDS[0] - oku += self.ORDINAL_TRIPLETS[i - 1] - return oku + wrd += self.CARDINAL_HUNDRED[0] + wrd += self.ORDINAL_TRIPLETS[i - 1] + return wrd else: - oku += self.CARDINAL_HUNDREDS[0] + wrd += self.CARDINAL_HUNDRED[0] - if not self.integers_to_read[0][son_okunan_basamak_sirasi + 1] == "0": + if not self.integers_to_read[0][last_read_digit_order + 1] == "0": if self.order_of_last_zero_digit == len(self.integers_to_read[0]) - ( - son_okunan_basamak_sirasi) - 2: + last_read_digit_order) - 2: if i == 1: - oku += self.ORDINAL_TENS[ - int(self.integers_to_read[0][son_okunan_basamak_sirasi + 1])] - return oku + wrd += self.ORDINAL_TENS.get( + self.integers_to_read[0][last_read_digit_order + 1], "") + return wrd elif i > 1: - oku += self.CARDINAL_TEN[ - int(self.integers_to_read[0][son_okunan_basamak_sirasi + 1])] - oku += self.ORDINAL_TRIPLETS[i - 1] - return oku + wrd += self.CARDINAL_TENS.get( + self.integers_to_read[0][last_read_digit_order + 1], "") + wrd += self.ORDINAL_TRIPLETS[i - 1] + return wrd else: - oku += self.CARDINAL_TEN[ - int(self.integers_to_read[0][son_okunan_basamak_sirasi + 1])] + wrd += self.CARDINAL_TENS.get(self.integers_to_read[0][last_read_digit_order + 1], + "") - if not self.integers_to_read[0][son_okunan_basamak_sirasi + 2] == "0": + if not self.integers_to_read[0][last_read_digit_order + 2] == "0": if self.order_of_last_zero_digit == len(self.integers_to_read[0]) - ( - son_okunan_basamak_sirasi) - 3: + last_read_digit_order) - 3: if i == 1: - oku += self.ORDINAL_ONES[ - int(self.integers_to_read[0][son_okunan_basamak_sirasi + 2])] - return oku + wrd += self.ORDINAL_ONES.get( + self.integers_to_read[0][last_read_digit_order + 2], "") + return wrd if i == 2: if not self.integers_to_read[0][ - son_okunan_basamak_sirasi: son_okunan_basamak_sirasi + 2] == "00": - oku += self.CARDINAL_ONES[ - int(self.integers_to_read[0][son_okunan_basamak_sirasi + 2])] - elif not self.integers_to_read[0][son_okunan_basamak_sirasi + 2] == "1": - oku += self.CARDINAL_ONES[ - int(self.integers_to_read[0][son_okunan_basamak_sirasi + 2])] - oku += self.ORDINAL_TRIPLETS[i - 1] - return oku + last_read_digit_order: last_read_digit_order + 2] == "00": + wrd += self.CARDINAL_ONES.get( + self.integers_to_read[0][last_read_digit_order + 2], "") + elif not self.integers_to_read[0][last_read_digit_order + 2] == "1": + wrd += self.CARDINAL_ONES.get( + self.integers_to_read[0][last_read_digit_order + 2], "") + wrd += self.ORDINAL_TRIPLETS[i - 1] + return wrd if i > 2: - oku += self.CARDINAL_ONES[ - int(self.integers_to_read[0][son_okunan_basamak_sirasi + 2])] - oku += self.ORDINAL_TRIPLETS[i - 1] - return oku + wrd += self.CARDINAL_ONES.get( + self.integers_to_read[0][last_read_digit_order + 2], "") + wrd += self.ORDINAL_TRIPLETS[i - 1] + return wrd else: if not self.integers_to_read[0][ - son_okunan_basamak_sirasi: son_okunan_basamak_sirasi + 2] == "00": - oku += self.CARDINAL_ONES[ - int(self.integers_to_read[0][son_okunan_basamak_sirasi + 2])] + last_read_digit_order: last_read_digit_order + 2] == "00": + wrd += self.CARDINAL_ONES.get( + self.integers_to_read[0][last_read_digit_order + 2], "") else: if not self.integers_to_read[0][ - son_okunan_basamak_sirasi: son_okunan_basamak_sirasi + 2] == "00": - oku += self.CARDINAL_ONES[ - int(self.integers_to_read[0][son_okunan_basamak_sirasi + 2])] - elif not self.integers_to_read[0][son_okunan_basamak_sirasi + 2] == "1": - oku += self.CARDINAL_ONES[ - int(self.integers_to_read[0][son_okunan_basamak_sirasi + 2])] + last_read_digit_order: last_read_digit_order + 2] == "00": + wrd += self.CARDINAL_ONES.get( + self.integers_to_read[0][last_read_digit_order + 2], "") + elif not self.integers_to_read[0][last_read_digit_order + 2] == "1": + wrd += self.CARDINAL_ONES.get( + self.integers_to_read[0][last_read_digit_order + 2], "") - oku += self.CARDINAL_TRIPLETS[i - 1] + wrd += self.CARDINAL_TRIPLETS[i - 1] - return oku + return wrd def to_ordinal_num(self, value): - oku = "" + wrd = "" isordinal = self.verify_ordinal(value) if isordinal: self.splitnum(value) - oku = self.integers_to_read[0] + self.ORDINAL_SIGN[0] + wrd = self.integers_to_read[0] + self.ORDINAL_SIGN[0] - return oku + return wrd # def inflect(self, value, text): diff --git a/tests/test_tr.py b/tests/test_tr.py index 46210b6..4cc9d4d 100644 --- a/tests/test_tr.py +++ b/tests/test_tr.py @@ -34,10 +34,18 @@ class Num2WordsTRTest(TestCase): self.assertEqual(num2words(101, True, "tr"), u"yüzbirinci") self.assertEqual(num2words(103, True, "tr"), u"yüzüçüncü") self.assertEqual(num2words(110, True, "tr"), u"yüzonuncu") + self.assertEqual(num2words(111, True, "tr"), u"yüzonbirinci") self.assertEqual(num2words(1000, True, "tr"), u"bininci") self.assertEqual(num2words(1001, True, "tr"), u"binbirinci") + self.assertEqual(num2words(1010, True, "tr"), u"binonuncu") + self.assertEqual(num2words(1011, True, "tr"), u"binonbirinci") + self.assertEqual(num2words(1100, True, "tr"), u"binyüzüncü") + self.assertEqual(num2words(1110, True, "tr"), u"binyüzonuncu") + self.assertEqual(num2words(2341, True, "tr"), u"ikibinüçyüzkırkbirinci") self.assertEqual(num2words(10000, True, "tr"), u"onbininci") + self.assertEqual(num2words(10010, True, "tr"), u"onbinonuncu") self.assertEqual(num2words(10100, True, "tr"), u"onbinyüzüncü") + self.assertEqual(num2words(10110, True, "tr"), u"onbinyüzonuncu") self.assertEqual(num2words(11000, True, "tr"), u"onbirbininci") self.assertEqual(num2words(35000, True, "tr"), u"otuzbeşbininci") self.assertEqual(num2words(116331, True, "tr"), u"yüzonaltıbinüçyüzotuzbirinci") @@ -70,10 +78,18 @@ class Num2WordsTRTest(TestCase): self.assertEqual(num2words(101, False, "tr"), u"yüzbir") self.assertEqual(num2words(103, False, "tr"), u"yüzüç") self.assertEqual(num2words(110, False, "tr"), u"yüzon") + self.assertEqual(num2words(111, False, "tr"), u"yüzonbir") self.assertEqual(num2words(1000, False, "tr"), u"bin") self.assertEqual(num2words(1001, False, "tr"), u"binbir") + self.assertEqual(num2words(1010, False, "tr"), u"binon") + self.assertEqual(num2words(1011, False, "tr"), u"binonbir") + self.assertEqual(num2words(1100, False, "tr"), u"binyüz") + self.assertEqual(num2words(1110, False, "tr"), u"binyüzon") + self.assertEqual(num2words(2341, False, "tr"), u"ikibinüçyüzkırkbir") self.assertEqual(num2words(10000, False, "tr"), u"onbin") + self.assertEqual(num2words(10010, False, "tr"), u"onbinon") self.assertEqual(num2words(10100, False, "tr"), u"onbinyüz") + self.assertEqual(num2words(10110, False, "tr"), u"onbinyüzon") self.assertEqual(num2words(11000, False, "tr"), u"onbirbin") self.assertEqual(num2words(35000, False, "tr"), u"otuzbeşbin") self.assertEqual(num2words(116331, False, "tr"), u"yüzonaltıbinüçyüzotuzbir") From bdc9b8e8ea7faa0158ac7b1985249c1432d58444 Mon Sep 17 00:00:00 2001 From: Tufan Kaynak <31142607+toofun666@users.noreply.github.com> Date: Mon, 4 Sep 2017 23:11:39 +0300 Subject: [PATCH 71/99] remove the last comma in dictionary --- num2words/lang_TR.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/num2words/lang_TR.py b/num2words/lang_TR.py index fe51b00..f716ea5 100644 --- a/num2words/lang_TR.py +++ b/num2words/lang_TR.py @@ -59,7 +59,7 @@ class Num2Word_TR(object): "6": u"altıncı", "7": u"yedinci", "8": u"sekizinci", - "9": u"dokuzuncu", + "9": u"dokuzuncu" } self.CARDINAL_TENS = { "1": u"on", From 5ff8e343a02dbecb6c55afbc84e915feb9480f77 Mon Sep 17 00:00:00 2001 From: Tufan Kaynak <31142607+toofun666@users.noreply.github.com> Date: Tue, 5 Sep 2017 08:10:42 +0300 Subject: [PATCH 72/99] unused elements stripped --- num2words/lang_TR.py | 51 ++++---------------------------------------- 1 file changed, 4 insertions(+), 47 deletions(-) diff --git a/num2words/lang_TR.py b/num2words/lang_TR.py index f716ea5..b2a0211 100644 --- a/num2words/lang_TR.py +++ b/num2words/lang_TR.py @@ -26,16 +26,11 @@ class Num2Word_TR(object): self.pointword = u"virgül" self.CURRENCY_UNIT = (u"lira",) self.CURRENCY_SUBUNIT = (u"kuruş",) - # type(%s) not in [long, int, float] self.errmsg_nonnum = u"Sadece sayılar yazıya çevrilebilir." - # Cannot treat float %s as ordinal. self.errmsg_floatord = u"Tam sayı olmayan {} sıralamada kullanılamaz." - # Cannot treat negative num %s as ordinal. self.errmsg_negord = u"Pozitif olmayan {} sıralamada kullanılamaz." - # abs(%s) must be less than %s. self.errmsg_toobig = u"abs({}) sayı yazıya çevirmek için çok büyük. Yazıya çevrilebilecek en büyük rakam {}." self.exclude_title = [] - # ordered number tuples in Turkish self.DECIMAL_SIGN = (",",) self.ORDINAL_SIGN = (".",) self.ZERO = (u"sıfır",) @@ -118,14 +113,6 @@ class Num2Word_TR(object): self.total_digits_outside_triplets = 0 self.order_of_last_zero_digit = 0 - # def set_numwords(self): - - # def gen_high_numwords(self, units, tens, lows): - - # def set_mid_numwords(self, mid): - - # def set_low_numwords(self, numwords): - def splitnum(self, value): return self.to_splitnum(value) @@ -155,7 +142,7 @@ class Num2Word_TR(object): if self.total_digits_outside_triplets == 1: if self.order_of_last_zero_digit == 0: - # number like x, read ordinal x and return + # number like x, read cardinal x and return wrd += self.CARDINAL_ONES.get(self.integers_to_read[0][0], "") return wrd @@ -337,12 +324,6 @@ class Num2Word_TR(object): wrd = self.to_cardinal(int(self.integers_to_read[0])) + wrd return wrd - # def merge(self, curr, next): - - # def clean(self, val): - - # def title(self, value): - def verify_cardinal(self, value): iscardinal = True try: @@ -367,10 +348,6 @@ class Num2Word_TR(object): raise OverflowError(self.errmsg_toobig.format(value, self.MAXVAL)) return isordinal - # def verify_num(self, value): - - # def set_wordnums(self): - def to_ordinal(self, value): wrd = "" isordinal = self.verify_ordinal(value) @@ -562,20 +539,9 @@ class Num2Word_TR(object): return wrd - def to_ordinal_num(self, value): - wrd = "" - isordinal = self.verify_ordinal(value) - if isordinal: - self.splitnum(value) - wrd = self.integers_to_read[0] + self.ORDINAL_SIGN[0] - - return wrd - - # def inflect(self, value, text): - - def to_splitnum(self, val, hightxt="", lowtxt="", jointxt="", divisor=100, longval=True, cents=True): - kesirlibolum = str(int(val * 10 ** self.precision)) - self.integers_to_read = [str(int(val)), kesirlibolum[len(kesirlibolum) - self.precision:]] + def to_splitnum(self, val): + float_digits = str(int(val * 10 ** self.precision)) + self.integers_to_read = [str(int(val)), float_digits[len(float_digits) - self.precision:]] if len(self.integers_to_read[0]) % 3 > 0: self.total_triplets_to_read = (len(self.integers_to_read[0]) // 3) + 1 elif len(self.integers_to_read[0]) % 3 == 0: @@ -591,18 +557,9 @@ class Num2Word_TR(object): else: found = 1 - def to_year(self, value, **kwargs): - return self.to_cardinal(value) - def to_currency(self, value, **kwargs): valueparts = self.to_cardinal(value).split(self.pointword) if len(valueparts) == 1: return valueparts[0] + self.CURRENCY_UNIT[0] if len(valueparts) == 2: return self.CURRENCY_UNIT[0].join(valueparts) + self.CURRENCY_SUBUNIT[0] - - # def base_setup(self): - - # def setup(self): - - # def test(self, value): From c3cec93c4db18fbf04694c09d70c751da56517f6 Mon Sep 17 00:00:00 2001 From: Tufan Kaynak <31142607+toofun666@users.noreply.github.com> Date: Tue, 5 Sep 2017 14:50:32 +0300 Subject: [PATCH 73/99] correction of 0.0n reading --- num2words/lang_TR.py | 5 ++++- tests/test_tr.py | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/num2words/lang_TR.py b/num2words/lang_TR.py index b2a0211..3bf2406 100644 --- a/num2words/lang_TR.py +++ b/num2words/lang_TR.py @@ -541,7 +541,10 @@ class Num2Word_TR(object): def to_splitnum(self, val): float_digits = str(int(val * 10 ** self.precision)) - self.integers_to_read = [str(int(val)), float_digits[len(float_digits) - self.precision:]] + if not int(val) == 0: + self.integers_to_read = [str(int(val)), float_digits[len(float_digits) - self.precision:]] + else: + self.integers_to_read = ["0", "0" * (self.precision - len(float_digits)) + float_digits[len(float_digits) - self.precision:]] if len(self.integers_to_read[0]) % 3 > 0: self.total_triplets_to_read = (len(self.integers_to_read[0]) // 3) + 1 elif len(self.integers_to_read[0]) % 3 == 0: diff --git a/tests/test_tr.py b/tests/test_tr.py index 4cc9d4d..3e9753d 100644 --- a/tests/test_tr.py +++ b/tests/test_tr.py @@ -111,6 +111,7 @@ class Num2WordsTRTest(TestCase): self.assertEqual(num2words(1101011010, False, "tr"), u"birmilyaryüzbirmilyononbirbinon") self.assertEqual(num2words(101101011010, False, "tr"), u"yüzbirmilyaryüzbirmilyononbirbinon") self.assertEqual(num2words(1000000000001, False, "tr"), u"birtrilyonbir") + self.assertEqual(num2words(0.01, False, "tr"), u"sıfırvirgülbir") self.assertEqual(num2words(0.1, False, "tr"), u"sıfırvirgülon") self.assertEqual(num2words(0.21, False, "tr"), u"sıfırvirgülyirmibir") self.assertEqual(num2words(1.01, False, "tr"), u"birvirgülbir") From 935d95a87f8e59341991982d51d3dd365ebad3f0 Mon Sep 17 00:00:00 2001 From: Tufan Kaynak <31142607+toofun666@users.noreply.github.com> Date: Tue, 5 Sep 2017 14:53:42 +0300 Subject: [PATCH 74/99] removed ineffective splitnum function --- num2words/lang_TR.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/num2words/lang_TR.py b/num2words/lang_TR.py index 3bf2406..dc3c26a 100644 --- a/num2words/lang_TR.py +++ b/num2words/lang_TR.py @@ -113,16 +113,13 @@ class Num2Word_TR(object): self.total_digits_outside_triplets = 0 self.order_of_last_zero_digit = 0 - def splitnum(self, value): - return self.to_splitnum(value) - def to_cardinal(self, value): wrd = "" is_cardinal = self.verify_cardinal(value) if is_cardinal: if not int(value) == value: return self.to_cardinal_float(value) - self.splitnum(value) + self.to_splitnum(value) if self.order_of_last_zero_digit >= len(self.integers_to_read[0]): # number like 00 and all 0s and even more, raise error @@ -309,7 +306,7 @@ class Num2Word_TR(object): return wrd def to_cardinal_float(self, value): - self.splitnum(value) + self.to_splitnum(value) wrd = "" wrd += self.pointword if len(self.integers_to_read[1]) >= 1: @@ -352,7 +349,7 @@ class Num2Word_TR(object): wrd = "" isordinal = self.verify_ordinal(value) if isordinal: - self.splitnum(value) + self.to_splitnum(value) if self.order_of_last_zero_digit >= len(self.integers_to_read[0]): # number like 00 and all 0s and even more, raise error From 873a3cc840dac7c3e847853d02f3719ac021befd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Legan=C3=A9s-Combarro=20=27piranna?= Date: Tue, 5 Sep 2017 17:35:30 +0200 Subject: [PATCH 75/99] Use `lang_FR` as base class for `lang_FR_CH` & clean-up linting for french --- num2words/lang_FR.py | 21 ++++++------- num2words/lang_FR_CH.py | 66 ++++++++--------------------------------- 2 files changed, 24 insertions(+), 63 deletions(-) diff --git a/num2words/lang_FR.py b/num2words/lang_FR.py index 1209eab..b151f12 100644 --- a/num2words/lang_FR.py +++ b/num2words/lang_FR.py @@ -21,6 +21,8 @@ from .lang_EU import Num2Word_EU class Num2Word_FR(Num2Word_EU): def setup(self): + Num2Word_EU.setup(self) + self.negword = "moins " self.pointword = "virgule" self.errmsg_nonnum = u"Seulement des nombres peuvent être convertis en mots." @@ -49,15 +51,14 @@ class Num2Word_FR(Num2Word_EU): else: if (not (cnum - 80)%100 or not cnum%100) and ctext[-1] == "s": ctext = ctext[:-1] - if (cnum<1000 and nnum != 1000 and ntext[-1] != "s" - and not nnum%100): + if cnum < 1000 and nnum != 1000 and ntext[-1] != "s" and not nnum % 100: ntext += "s" if nnum < cnum < 100: if nnum % 10 == 1 and cnum != 80: return ("%s et %s"%(ctext, ntext), cnum + nnum) return ("%s-%s"%(ctext, ntext), cnum + nnum) - elif nnum > cnum: + if nnum > cnum: return ("%s %s"%(ctext, ntext), cnum * nnum) return ("%s %s"%(ctext, ntext), cnum + nnum) @@ -83,15 +84,15 @@ class Num2Word_FR(Num2Word_EU): def to_ordinal_num(self, value): self.verify_ordinal(value) out = str(value) - out += {"1" : "er" }.get(out[-1], "me") + out += {"1" : "er"}.get(out[-1], "me") return out def to_currency(self, val, longval=True, old=False): hightxt = "Euro/s" if old: - hightxt="franc/s" + hightxt = "franc/s" return self.to_splitnum(val, hightxt=hightxt, lowtxt="centime/s", - jointxt="et",longval=longval) + jointxt="et", longval=longval) n2w = Num2Word_FR() to_card = n2w.to_cardinal @@ -99,10 +100,10 @@ to_ord = n2w.to_ordinal to_ordnum = n2w.to_ordinal_num def main(): - for val in [ 1, 11, 12, 21, 31, 33, 71, 80, 81, 91, 99, 100, 101, 102, 155, - 180, 300, 308, 832, 1000, 1001, 1061, 1100, 1500, 1701, 3000, - 8280, 8291, 150000, 500000, 1000000, 2000000, 2000001, - -21212121211221211111, -2.121212, -1.0000100]: + for val in [1, 11, 12, 21, 31, 33, 71, 80, 81, 91, 99, 100, 101, 102, 155, + 180, 300, 308, 832, 1000, 1001, 1061, 1100, 1500, 1701, 3000, + 8280, 8291, 150000, 500000, 1000000, 2000000, 2000001, + -21212121211221211111, -2.121212, -1.0000100]: n2w.test(val) n2w.test(1325325436067876801768700107601001012212132143210473207540327057320957032975032975093275093275093270957329057320975093272950730) diff --git a/num2words/lang_FR_CH.py b/num2words/lang_FR_CH.py index b6d40a0..032c86f 100644 --- a/num2words/lang_FR_CH.py +++ b/num2words/lang_FR_CH.py @@ -16,27 +16,17 @@ # MA 02110-1301 USA from __future__ import unicode_literals, print_function -from .lang_EU import Num2Word_EU +from .lang_FR import Num2Word_FR -class Num2Word_FR_CH(Num2Word_EU): + +class Num2Word_FR_CH(Num2Word_FR): def setup(self): - self.negword = "moins " - self.pointword = "virgule" - self.errmsg_nonnum = u"Seulement des nombres peuvent être convertis en mots." - self.errmsg_toobig = u"Nombre trop grand pour être converti en mots." - self.exclude_title = ["et", "virgule", "moins"] + Num2Word_FR.setup(self) + self.mid_numwords = [(1000, "mille"), (100, "cent"), (90, "nonante"), - (80, "huitante"), (70, "septante"), (60, "soixante"), + (80, "huitante"), (70, "septante"), (60, "soixante"), (50, "cinquante"), (40, "quarante"), (30, "trente")] - self.low_numwords = ["vingt", "dix-neuf", "dix-huit", "dix-sept", - "seize", "quinze", "quatorze", "treize", "douze", - "onze", "dix", "neuf", "huit", "sept", "six", - "cinq", "quatre", "trois", "deux", "un", "zéro"] - self.ords = { - "cinq": "cinquième", - "neuf": "neuvième", - } def merge(self, curr, next): @@ -45,59 +35,29 @@ class Num2Word_FR_CH(Num2Word_EU): if cnum == 1: if nnum < 1000000: return next + if cnum < 1000 and nnum != 1000 and ntext[-1] != "s" and not nnum % 100: - ntext += "s" + ntext += "s" if nnum < cnum < 100: if nnum % 10 == 1: return ("%s et %s"%(ctext, ntext), cnum + nnum) return ("%s-%s"%(ctext, ntext), cnum + nnum) - elif nnum > cnum: + if nnum > cnum: return ("%s %s"%(ctext, ntext), cnum * nnum) return ("%s %s"%(ctext, ntext), cnum + nnum) - # Is this right for such things as 1001 - "mille unième" instead of - # "mille premier"?? "millième"?? - - def to_ordinal(self,value): - self.verify_ordinal(value) - if value == 1: - return "premier" - word = self.to_cardinal(value) - for src, repl in self.ords.items(): - if word.endswith(src): - word = word[:-len(src)] + repl - break - else: - if word[-1] == "e": - word = word[:-1] - word = word + "ième" - return word - - def to_ordinal_num(self, value): - self.verify_ordinal(value) - out = str(value) - out += {"1" : "er" }.get(out[-1], "me") - return out - - def to_currency(self, val, longval=True, old=False): - hightxt = "Euro/s" - if old: - hightxt="franc/s" - return self.to_splitnum(val, hightxt=hightxt, lowtxt="centime/s", - jointxt="et",longval=longval) - n2w = Num2Word_FR_CH() to_card = n2w.to_cardinal to_ord = n2w.to_ordinal to_ordnum = n2w.to_ordinal_num def main(): - for val in [ 1, 11, 12, 21, 31, 33, 71, 80, 81, 91, 99, 100, 101, 102, 155, - 180, 300, 308, 832, 1000, 1001, 1061, 1100, 1500, 1701, 3000, - 8280, 8291, 150000, 500000, 1000000, 2000000, 2000001, - -21212121211221211111, -2.121212, -1.0000100]: + for val in [1, 11, 12, 21, 31, 33, 71, 80, 81, 91, 99, 100, 101, 102, 155, + 180, 300, 308, 832, 1000, 1001, 1061, 1100, 1500, 1701, 3000, + 8280, 8291, 150000, 500000, 1000000, 2000000, 2000001, + -21212121211221211111, -2.121212, -1.0000100]: n2w.test(val) n2w.test(1325325436067876801768700107601001012212132143210473207540327057320957032975032975093275093275093270957329057320975093272950730) From 3e95697b0819a5aea7b8d589f4e92ca3d2582ab8 Mon Sep 17 00:00:00 2001 From: Tufan Kaynak <31142607+toofun666@users.noreply.github.com> Date: Tue, 5 Sep 2017 21:50:43 +0300 Subject: [PATCH 76/99] Turkish language added to list --- README.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/README.rst b/README.rst index 606b1ca..4345aaa 100644 --- a/README.rst +++ b/README.rst @@ -60,6 +60,7 @@ Besides the numerical argument, there's two optional arguments. * ``pt_BR`` (Brazilian Portuguese) * ``he`` (Hebrew) * ``it`` (Italian) +* ``tr`` (Turkish) You can supply values like ``fr_FR``, the code will be correctly interpreted. If you supply an unsupported language, ``NotImplementedError`` is raised. From 29d9d2a33615f692640e72d218bc3950ed6d52e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Legan=C3=A9s-Combarro=20=27piranna?= Date: Tue, 5 Sep 2017 22:36:37 +0200 Subject: [PATCH 77/99] Converted tabs indention to spaces --- tests/test_pl.py | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/tests/test_pl.py b/tests/test_pl.py index b70b9a6..e21a852 100644 --- a/tests/test_pl.py +++ b/tests/test_pl.py @@ -22,28 +22,28 @@ from num2words import num2words from num2words.lang_PL import to_currency class Num2WordsPLTest(TestCase): - def test_cardinal(self): - self.assertEqual(num2words(100, lang='pl'), "sto") - self.assertEqual(num2words(101, lang='pl'), "sto jeden") - self.assertEqual(num2words(110, lang='pl'), "sto dziesięć") - self.assertEqual(num2words(115, lang='pl'), "sto piętnaście") - self.assertEqual(num2words(123, lang='pl'), "sto dwadzieścia trzy") - self.assertEqual(num2words(1000, lang='pl'), "tysiąc") - self.assertEqual(num2words(1001, lang='pl'), "tysiąc jeden") - self.assertEqual(num2words(2012, lang='pl'), "dwa tysiące dwanaście") - self.assertEqual(num2words(12519.85, lang='pl'), "dwanaście tysięcy pięćset dziewiętnaście przecinek osiemdziesiąt pięć") - self.assertEqual(num2words(123.50, lang='pl'), "sto dwadzieścia trzy przecinek pięć") - self.assertEqual(num2words(1234567890, lang='pl'), "miliard dwieście trzydzieści cztery miliony pięćset sześćdziesiąt siedem tysięcy osiemset dziewięćdzisiąt") - self.assertEqual(num2words(215461407892039002157189883901676, lang='pl'), "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ść") - self.assertEqual(num2words(719094234693663034822824384220291, lang='pl'), "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") + def test_cardinal(self): + self.assertEqual(num2words(100, lang='pl'), "sto") + self.assertEqual(num2words(101, lang='pl'), "sto jeden") + self.assertEqual(num2words(110, lang='pl'), "sto dziesięć") + self.assertEqual(num2words(115, lang='pl'), "sto piętnaście") + self.assertEqual(num2words(123, lang='pl'), "sto dwadzieścia trzy") + self.assertEqual(num2words(1000, lang='pl'), "tysiąc") + self.assertEqual(num2words(1001, lang='pl'), "tysiąc jeden") + self.assertEqual(num2words(2012, lang='pl'), "dwa tysiące dwanaście") + self.assertEqual(num2words(12519.85, lang='pl'), "dwanaście tysięcy pięćset dziewiętnaście przecinek osiemdziesiąt pięć") + self.assertEqual(num2words(123.50, lang='pl'), "sto dwadzieścia trzy przecinek pięć") + self.assertEqual(num2words(1234567890, lang='pl'), "miliard dwieście trzydzieści cztery miliony pięćset sześćdziesiąt siedem tysięcy osiemset dziewięćdzisiąt") + self.assertEqual(num2words(215461407892039002157189883901676, lang='pl'), "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ść") + self.assertEqual(num2words(719094234693663034822824384220291, lang='pl'), "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") - 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'), "tysiąc dwieście trzydzieści cztery euro, pięćdziesiąt sześć centów") - self.assertEqual(to_currency(1234.56, 'PLN'), "tysiąc dwieście trzydzieści cztery złote, pięćdziesiąt sześć groszy") - self.assertEqual(to_currency(10111, 'EUR', seperator=' i'), "sto jeden euro i jedenaście centów") - self.assertEqual(to_currency(10121, 'PLN', seperator=' i'), "sto jeden złotych i dwadzieścia jeden groszy") - self.assertEqual(to_currency(-1251985, 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'), "sto dwadzieścia trzy złote i pięćdziesiąt groszy") - self.assertEqual(to_currency(1950, cents = False), "dziewiętnaście euro, 50 centów") + 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'), "tysiąc dwieście trzydzieści cztery euro, pięćdziesiąt sześć centów") + self.assertEqual(to_currency(1234.56, 'PLN'), "tysiąc dwieście trzydzieści cztery złote, pięćdziesiąt sześć groszy") + self.assertEqual(to_currency(10111, 'EUR', seperator=' i'), "sto jeden euro i jedenaście centów") + self.assertEqual(to_currency(10121, 'PLN', seperator=' i'), "sto jeden złotych i dwadzieścia jeden groszy") + self.assertEqual(to_currency(-1251985, 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'), "sto dwadzieścia trzy złote i pięćdziesiąt groszy") + self.assertEqual(to_currency(1950, cents = False), "dziewiętnaście euro, 50 centów") From 8ecd10f0554287f0f0e27f85164c7d87d1f52ba1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Legan=C3=A9s-Combarro=20=27piranna?= Date: Tue, 5 Sep 2017 22:42:45 +0200 Subject: [PATCH 78/99] [fix] Allow to pass `float`s to `Num2Word_Base.to_splitnum()` --- num2words/base.py | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/num2words/base.py b/num2words/base.py index 272d5bb..e1e4383 100644 --- a/num2words/base.py +++ b/num2words/base.py @@ -111,13 +111,7 @@ class Num2Word_Base(object): return self.title(out + words) - def to_cardinal_float(self, value): - try: - float(value) == value - except (ValueError, TypeError, AssertionError): - raise TypeError(self.errmsg_nonnum % value) - - value = float(value) + def float2tuple(self, value): pre = int(value) post = abs(value - pre) * 10**self.precision if abs(round(post) - post) < 0.01: @@ -127,6 +121,18 @@ class Num2Word_Base(object): post = int(round(post)) else: post = int(math.floor(post)) + + return pre, post + + + def to_cardinal_float(self, value): + try: + float(value) == value + except (ValueError, TypeError, AssertionError): + raise TypeError(self.errmsg_nonnum % value) + + pre, post = self.float2tuple(float(value)) + post = str(post) post = '0' * (self.precision - len(post)) + post @@ -213,12 +219,17 @@ class Num2Word_Base(object): #//CHECK: generalise? Any others like pounds/shillings/pence? def to_splitnum(self, val, hightxt="", lowtxt="", jointxt="", - divisor=100, longval=True, cents = True): + divisor=100, longval=True, cents=True): out = [] - try: - high, low = val - except TypeError: - high, low = divmod(val, divisor) + + if isinstance(val, float): + high, low = self.float2tuple(val) + else: + try: + high, low = val + except TypeError: + high, low = divmod(val, divisor) + if high: hightxt = self.title(self.inflect(high, hightxt)) out.append(self.to_cardinal(high)) @@ -230,6 +241,7 @@ class Num2Word_Base(object): out.append(self.title(jointxt)) elif hightxt: out.append(hightxt) + if low: if cents: out.append(self.to_cardinal(low)) @@ -237,6 +249,7 @@ class Num2Word_Base(object): out.append("%02d" % low) if lowtxt and longval: out.append(self.title(self.inflect(low, lowtxt))) + return " ".join(out) From 614255bbdea395365a7aa366457b32b0e83a6f78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Legan=C3=A9s-Combarro=20=27piranna?= Date: Tue, 5 Sep 2017 22:43:21 +0200 Subject: [PATCH 79/99] Add `fr_DZ` locale --- num2words/__init__.py | 2 ++ num2words/lang_FR_DZ.py | 48 +++++++++++++++++++++++++++++++++++++++++ tests/test_fr_dz.py | 27 +++++++++++++++++++++++ 3 files changed, 77 insertions(+) create mode 100644 num2words/lang_FR_DZ.py create mode 100644 tests/test_fr_dz.py diff --git a/num2words/__init__.py b/num2words/__init__.py index 58eabfb..3fc0c37 100644 --- a/num2words/__init__.py +++ b/num2words/__init__.py @@ -22,6 +22,7 @@ from . import lang_EN_GB from . import lang_EN_IN from . import lang_FR from . import lang_FR_CH +from . import lang_FR_DZ from . import lang_DE from . import lang_ES from . import lang_LT @@ -47,6 +48,7 @@ CONVERTER_CLASSES = { 'en_IN': lang_EN_IN.Num2Word_EN_IN(), 'fr': lang_FR.Num2Word_FR(), 'fr_CH': lang_FR_CH.Num2Word_FR_CH(), + 'fr_DZ': lang_FR_DZ.Num2Word_FR_DZ(), 'de': lang_DE.Num2Word_DE(), 'es': lang_ES.Num2Word_ES(), 'es_CO': lang_ES_CO.Num2Word_ES_CO(), diff --git a/num2words/lang_FR_DZ.py b/num2words/lang_FR_DZ.py new file mode 100644 index 0000000..d513101 --- /dev/null +++ b/num2words/lang_FR_DZ.py @@ -0,0 +1,48 @@ +# 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 .lang_FR import Num2Word_FR + + +class Num2Word_FR_DZ(Num2Word_FR): + def to_currency(self, val, longval=True, cents=True, jointxt="virgule"): + return self.to_splitnum(val, hightxt="dinard/s", lowtxt="centime/s", + jointxt=jointxt, longval=longval, cents=cents) + + +n2w = Num2Word_FR_DZ() +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(1325325436067876801768700107601001012212132143210473207540327057320957032975032975093275093275093270957329057320975093272950730) + for val in [1, 120, 1000, 1120, 1800, 1976, 2000, 2010, 2099, 2171]: + print val, "is", n2w.to_currency(val) + print val, "is", n2w.to_year(val) + + +if __name__ == "__main__": + main() diff --git a/tests/test_fr_dz.py b/tests/test_fr_dz.py new file mode 100644 index 0000000..2463740 --- /dev/null +++ b/tests/test_fr_dz.py @@ -0,0 +1,27 @@ +# -*- encoding: utf-8 -*- +# Copyright (c) 2015, 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 unittest import TestCase + +from num2words import num2words +from num2words.lang_FR_DZ import to_currency + +class Num2WordsPLTest(TestCase): + def test_currency(self): + self.assertEqual(to_currency(1234.12), "mille deux cent trente-quatre dinards virgule douze centimes") + self.assertEqual(to_currency(45689.89), "quarante-cinq mille six cent quatre-vingt-neuf dinards virgule quatre-vingt-neuf centimes") From 97e1464550113b130eb6eecb8dfdaa5fb9696858 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Legan=C3=A9s-Combarro=20=27piranna?= Date: Wed, 6 Sep 2017 09:13:14 +0200 Subject: [PATCH 80/99] Minor fix to make code Python 3 compatible --- num2words/lang_FR_DZ.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/num2words/lang_FR_DZ.py b/num2words/lang_FR_DZ.py index d513101..5fddbf8 100644 --- a/num2words/lang_FR_DZ.py +++ b/num2words/lang_FR_DZ.py @@ -40,8 +40,8 @@ def main(): n2w.test(1325325436067876801768700107601001012212132143210473207540327057320957032975032975093275093275093270957329057320975093272950730) for val in [1, 120, 1000, 1120, 1800, 1976, 2000, 2010, 2099, 2171]: - print val, "is", n2w.to_currency(val) - print val, "is", n2w.to_year(val) + print(val, "is", n2w.to_currency(val)) + print(val, "is", n2w.to_year(val)) if __name__ == "__main__": From 849b55d95c7fa091859e988672464a59566f3763 Mon Sep 17 00:00:00 2001 From: Tufan Kaynak <31142607+toofun666@users.noreply.github.com> Date: Wed, 6 Sep 2017 14:37:28 +0300 Subject: [PATCH 81/99] README update --- README.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 4345aaa..9762993 100644 --- a/README.rst +++ b/README.rst @@ -5,8 +5,9 @@ num2words - Convert numbers to words in multiple languages :target: https://travis-ci.org/savoirfairelinux/num2words ``num2words`` is a library that converts numbers like ``42`` to words like ``forty-two``. It -supports multiple languages (English, French, Spanish, German and Lithuanian) and can even generate -ordinal numbers like ``forty-second`` (altough this last feature is a bit buggy at the moment). +supports multiple languages (see the list below for full list of languages) and can even generate +ordinal numbers like ``forty-second`` (although this last feature is a bit buggy for some +languages at the moment). The project is hosted on https://github.com/savoirfairelinux/num2words From fc05dcdd2a867e5cde80f92d79f00352ab1ee9c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Legan=C3=A9s-Combarro=20=27piranna?= Date: Wed, 6 Sep 2017 22:59:20 +0200 Subject: [PATCH 82/99] Added reference to `fr_DZ` locale on readme & clean-up --- README.rst | 49 +++++++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/README.rst b/README.rst index 606b1ca..813e87f 100644 --- a/README.rst +++ b/README.rst @@ -4,9 +4,11 @@ num2words - Convert numbers to words in multiple languages .. image:: https://travis-ci.org/savoirfairelinux/num2words.svg?branch=master :target: https://travis-ci.org/savoirfairelinux/num2words -``num2words`` is a library that converts numbers like ``42`` to words like ``forty-two``. It -supports multiple languages (English, French, Spanish, German and Lithuanian) and can even generate -ordinal numbers like ``forty-second`` (altough this last feature is a bit buggy at the moment). +``num2words`` is a library that converts numbers like ``42`` to words like +``forty-two``. It supports multiple languages (English, Arabic, Danish, French, +German, Hebrew, Italian, Latvian, Norwegian, Polish, Portuguese, Russian, +Spanish and Lithuanian) and can even generate ordinal numbers like +``forty-second`` (altough this last feature is a bit buggy at the moment). The project is hosted on https://github.com/savoirfairelinux/num2words @@ -40,29 +42,32 @@ There's only one function to use:: Besides the numerical argument, there's two optional arguments. -**ordinal:** A boolean flag indicating to return an ordinal number instead of a cardinal one. +**ordinal:** A boolean flag indicating to return an ordinal number instead of a +cardinal one. **lang:** The language in which to convert the number. Supported values are: -* ``en`` (English, default) * ``ar`` (Arabic) -* ``fr`` (French) * ``de`` (German) -* ``es`` (Spanish) -* ``lt`` (Lithuanian) -* ``lv`` (Latvian) +* ``dk`` (Danish) +* ``en`` (English, default) * ``en_GB`` (British English) * ``en_IN`` (Indian English) -* ``no`` (Norwegian) -* ``pl`` (Polish) -* ``ru`` (Russian) -* ``dk`` (Danish) -* ``pt_BR`` (Brazilian Portuguese) +* ``es`` (Spanish) +* ``fr`` (French) +* ``fr_CH`` (Swiss French) +* ``fr_DZ`` (Argelia French) * ``he`` (Hebrew) * ``it`` (Italian) +* ``lt`` (Lithuanian) +* ``lv`` (Latvian) +* ``no`` (Norwegian) +* ``pl`` (Polish) +* ``pt_BR`` (Brazilian Portuguese) +* ``ru`` (Russian) -You can supply values like ``fr_FR``, the code will be -correctly interpreted. If you supply an unsupported language, ``NotImplementedError`` is raised. +You can supply values like ``fr_FR``, the code will be correctly interpreted. If +you supply an unsupported language, ``NotImplementedError`` is raised. Therefore, if you want to call ``num2words`` with a fallback, you can do:: try: @@ -73,12 +78,12 @@ Therefore, if you want to call ``num2words`` with a fallback, you can do:: History ------- -``num2words`` is based on an old library, ``pynum2word`` created by Taro Ogawa in 2003. -Unfortunately, the library stopped being maintained and the author can't be reached. There was -another developer, Marius Grigaitis, who in 2011 added Lithuanian support, but didn't take over -maintenance of the project. +``num2words`` is based on an old library, ``pynum2word`` created by Taro Ogawa +in 2003. Unfortunately, the library stopped being maintained and the author +can't be reached. There was another developer, Marius Grigaitis, who in 2011 +added Lithuanian support, but didn't take over maintenance of the project. -I am thus basing myself on Marius Grigaitis' improvements and re-publishing ``pynum2word`` as -``num2words``. +I am thus basing myself on Marius Grigaitis' improvements and re-publishing +``pynum2word`` as ``num2words``. Virgil Dupras, Savoir-faire Linux From a9546c608b79b57670047d0559d5d796ee132844 Mon Sep 17 00:00:00 2001 From: Tufan Kaynak <31142607+toofun666@users.noreply.github.com> Date: Thu, 7 Sep 2017 09:39:20 +0300 Subject: [PATCH 83/99] readme corrected --- README.rst | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/README.rst b/README.rst index 813e87f..6eb5588 100644 --- a/README.rst +++ b/README.rst @@ -5,10 +5,9 @@ num2words - Convert numbers to words in multiple languages :target: https://travis-ci.org/savoirfairelinux/num2words ``num2words`` is a library that converts numbers like ``42`` to words like -``forty-two``. It supports multiple languages (English, Arabic, Danish, French, -German, Hebrew, Italian, Latvian, Norwegian, Polish, Portuguese, Russian, -Spanish and Lithuanian) and can even generate ordinal numbers like -``forty-second`` (altough this last feature is a bit buggy at the moment). +``forty-two``. It supports multiple languages (see the list below for full list +of languages) and can even generate ordinal numbers like ``forty-second`` +(although this last feature is a bit buggy for some languages at the moment). The project is hosted on https://github.com/savoirfairelinux/num2words @@ -47,17 +46,21 @@ cardinal one. **lang:** The language in which to convert the number. Supported values are: +* ``en`` (English, default) * ``ar`` (Arabic) * ``de`` (German) * ``dk`` (Danish) -* ``en`` (English, default) -* ``en_GB`` (British English) -* ``en_IN`` (Indian English) +* ``en_GB`` (English - Great Britain) +* ``en_IN`` (English - India) * ``es`` (Spanish) +* ``es_CO`` (Spanish - Colombia) +* ``es_VE`` (Spanish - Venezuela) +* ``eu`` (EURO) * ``fr`` (French) -* ``fr_CH`` (Swiss French) -* ``fr_DZ`` (Argelia French) +* ``fr_CH`` (French - Switzerland) +* ``fr_DZ`` (French - Algeria) * ``he`` (Hebrew) +* ``id`` (Indonesian) * ``it`` (Italian) * ``lt`` (Lithuanian) * ``lv`` (Latvian) @@ -65,6 +68,8 @@ cardinal one. * ``pl`` (Polish) * ``pt_BR`` (Brazilian Portuguese) * ``ru`` (Russian) +* ``tr`` (Turkish) +* ``vn`` (Vietnamese) You can supply values like ``fr_FR``, the code will be correctly interpreted. If you supply an unsupported language, ``NotImplementedError`` is raised. From 4047d6526a46738ca6676c9a69e1aafb021ee25a Mon Sep 17 00:00:00 2001 From: Armin Date: Fri, 8 Sep 2017 13:17:14 +0200 Subject: [PATCH 84/99] added support for Dutch (NL) language --- num2words/__init__.py | 5 +- num2words/lang_NL.py | 155 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 158 insertions(+), 2 deletions(-) create mode 100644 num2words/lang_NL.py diff --git a/num2words/__init__.py b/num2words/__init__.py index 58eabfb..6589569 100644 --- a/num2words/__init__.py +++ b/num2words/__init__.py @@ -38,7 +38,7 @@ from . import lang_ES_VE from . import lang_ES_CO from . import lang_VN from . import lang_TR - +from . import lang_NL CONVERTER_CLASSES = { 'ar': lang_AR.Num2Word_AR(), @@ -62,7 +62,8 @@ CONVERTER_CLASSES = { 'he': lang_HE.Num2Word_HE(), 'it': lang_IT.Num2Word_IT(), 'vi_VN': lang_VN.Num2Word_VN(), - 'tr': lang_TR.Num2Word_TR() + 'tr': lang_TR.Num2Word_TR(), + 'nl': lang_NL.Num2Word_NL() } def num2words(number, ordinal=False, lang='en'): diff --git a/num2words/lang_NL.py b/num2words/lang_NL.py new file mode 100644 index 0000000..2447f7e --- /dev/null +++ b/num2words/lang_NL.py @@ -0,0 +1,155 @@ +# -*- 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, print_function +from .lang_EU import Num2Word_EU + +class Num2Word_NL(Num2Word_EU): + def set_high_numwords(self, high): + max = 3 + 6*len(high) + + for word, n in zip(high, range(max, 3, -6)): + self.cards[10**n] = word + "iljard" + self.cards[10**(n-3)] = word + "iljoen" + + def setup(self): + self.negword = "min " + self.pointword = "komma" + self.errmsg_floatord = "Het zwevende puntnummer %s kan niet omgezet worden naar een ordernummer." # "Cannot treat float %s as ordinal." + self.errmsg_nonnum = "Alleen nummers (type (%s)) kunnen naar woorden omgezet worden." # "type(((type(%s)) ) not in [long, int, float]" + self.errmsg_negord = "Het negatieve getal %s kan niet omgezet worden naar een ordernummer." # "Cannot treat negative num %s as ordinal." + self.errmsg_toobig = "Het getal %s moet minder zijn dan %s." # "abs(%s) must be less than %s." + self.exclude_title = [] + + lows = ["non", "okt", "sept", "sext", "quint", "quadr", "tr", "b", "m"] + units = ["", "un", "duo", "tre", "quattuor", "quin", "sex", "sept", + "okto", "novem"] + tens = ["dez", "vigint", "trigint", "quadragint", "quinquagint", + "sexagint", "septuagint", "oktogint", "nonagint"] + + + + + self.high_numwords = ["zend"]+self.gen_high_numwords(units, tens, lows) + self.mid_numwords = [(1000, "duizend"), (100, "honderd"), + (90, "negentig"), (80, "tachtig"), (70, "zeventig"), + (60, "zestig"), (50, "vijftig"), (40, "veertig"), + (30, "dertig")] + self.low_numwords = ["twintig", "negentien", "achttien", "zeventien", + "zestien", "vijftien", "veertien", "dertien", + "twaalf", "elf", "tien", "negen", "acht", "zeven", + "zes", "vijf", "vier", "drie", "twee", "één", + "nul"] + + self.ords = {"één": "eerst", + "twee": "tweed", + "drie": "derd", + "vier": "vierd", + "vijf": "vijfd", + "zes": "zesd", + "zeven": "zevend", + "acht": "achtst", + "negen": "negend", + "tien":"tiend", + "elf":"elfde", + "twaalf":"twaalfde", + + "ig": "igst", + "erd": "erdst", + "end": "endst", + "joen": "joenst", + "rd": "rdst"} + + def merge(self, curr, next): + ctext, cnum, ntext, nnum = curr + next + + if cnum == 1: + if nnum < 10**6: + return next + ctext = "een" + + if nnum > cnum: + if nnum >= 10**6: + ctext += " " + val = cnum * nnum + else: + if nnum < 10 < cnum < 100: + if nnum == 1: + ntext = "een" + + if ntext.endswith("e"): + ntext += "ën"#"n" + else: + ntext += "en" + ntext, ctext = ctext, ntext #+ "en" + elif cnum >= 10**6: + ctext += " " + val = cnum + nnum + + word = ctext + ntext + return (word, val) + + def to_ordinal(self, value): + self.verify_ordinal(value) + outword = self.to_cardinal(value) + for key in self.ords: + if outword.endswith(key): + outword = outword[:len(outword) - len(key)] + self.ords[key] + break + return outword + "e" + + def to_ordinal_num(self, value): + self.verify_ordinal(value) + return str(value) + "." + + def to_currency(self, val, longval=True, old=False): + if old: + return self.to_splitnum(val, hightxt="euro/s", lowtxt="cent/s", + jointxt="en",longval=longval) + return super(Num2Word_NL, self).to_currency(val, jointxt="en", + longval=longval) + + def to_year(self, val, longval=True): + if not (val//100)%10: + return self.to_cardinal(val) + return self.to_splitnum(val, hightxt="honderd", longval=longval) + +n2w = Num2Word_NL() +to_card = n2w.to_cardinal +to_ord = n2w.to_ordinal +to_ordnum = n2w.to_ordinal_num + + +def main(): + for val in [1, 7, 8, 12, 17, 62,81, 91, 99, 100, 101, 102, 155, + 180, 300, 308, 832, 1000, 1001, 1061,1062, 1100, 1500, 1701, 3000, + 8280, 8291, 150000, 500000, 3000000, 1000000, 2000001, 1000000000, 2000000000, + -21212121211221211111, -2.121212, -1.0000100]: + n2w.test(val) + + # n2w.test(1325325436067876801768700107601001012212132143210473207540327057320957032975032975093275093275093270957329057320975093272950730) + n2w.test(3000000) + n2w.test(3000000000001) + n2w.test(3000000324566) + print(n2w.to_currency(112121)) + print(n2w.to_year(2000)) + print(n2w.to_year(1820)) + print(n2w.to_year(2001)) + +if __name__ == "__main__": + main() + From 77df034a706d9cecbf8582d59197d99de70ca331 Mon Sep 17 00:00:00 2001 From: Sergio Zholudov Date: Fri, 8 Sep 2017 17:37:38 +0300 Subject: [PATCH 85/99] Ukrainian language --- num2words/lang_UK.py | 316 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 316 insertions(+) create mode 100644 num2words/lang_UK.py diff --git a/num2words/lang_UK.py b/num2words/lang_UK.py new file mode 100644 index 0000000..14d04b6 --- /dev/null +++ b/num2words/lang_UK.py @@ -0,0 +1,316 @@ +# -*- encoding: utf-8 -*- +# Copyright (c) 2003, Taro Ogawa. All Rights Reserved. +# Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. + +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301 USA +u""" +>>> from textwrap import fill + +>>> ' '.join([str(i) for i in splitby3('1')]) +u'1' +>>> ' '.join([str(i) for i in splitby3('1123')]) +u'1 123' +>>> ' '.join([str(i) for i in splitby3('1234567890')]) +u'1 234 567 890' + +>>> print(' '.join([n2w(i) for i in range(10)])) +нуль один два три чотири п'ять ш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 + +ZERO = (u'нуль',) + +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'дев\'ять',), +} + +ONES = { + 1: (u'один',), + 2: (u'два',), + 3: (u'три',), + 4: (u'чотири',), + 5: (u'п\'ять',), + 6: (u'шiсть',), + 7: (u'сiм',), + 8: (u'вiсiм',), + 9: (u'дев\'ять',), +} + +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'дев\'ятнадцять',), +} + +TWENTIES = { + 2: (u'двадцять',), + 3: (u'тридцять',), + 4: (u'сорок',), + 5: (u'п\'ятдесят',), + 6: (u'шiстдесят',), + 7: (u'сiмдесят',), + 8: (u'вiсiмдесят',), + 9: (u'дев\'яносто',), +} + +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'дев\'ятсот',), +} + +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в') + ), +} + + +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): + #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 (n % 10 > 1 and n % 10 < 5): + form = 1 + else: + form = 2 + else: + form = 2 + + return forms[form] + + +def int2word(n, feminine=True): + if n < 0: + return ' '.join([u'мiнус', 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(pluralize(x, THOUSANDS[i])) + + return ' '.join(words) + + +def n2w(n): + n = str(n).replace(',', '.') + if '.' in n: + left, right = n.split('.') + return u'%s кома %s' % (int2word(int(left)), int2word(int(right))) + else: + return int2word(int(n)) + + +def to_currency(n, currency='EUR', cents=True, seperator=','): + if type(n) == int: + if n < 0: + minus = True + else: + minus = False + + n = abs(n) + left = n / 100 + right = n % 100 + else: + n = str(n).replace(',', '.') + if '.' in n: + left, right = n.split('.') + else: + left, right = n, 0 + left, right = int(left), int(right) + minus = False + cr1, cr2 = CURRENCIES[currency] + + if minus: + minus_str = "мiнус " + else: + minus_str = "" + + 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 to_ordinal(self, number): + raise NotImplementedError() + + +if __name__ == '__main__': + import doctest + doctest.testmod() From 8b12fa7dc352d29e65e06e4ddfe658f4471f741f Mon Sep 17 00:00:00 2001 From: Sergio Zholudov Date: Fri, 8 Sep 2017 17:44:27 +0300 Subject: [PATCH 86/99] Updated __init__.py, added Ukrainian --- num2words/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/num2words/__init__.py b/num2words/__init__.py index 3fc0c37..aa956a3 100644 --- a/num2words/__init__.py +++ b/num2words/__init__.py @@ -39,6 +39,7 @@ from . import lang_ES_VE from . import lang_ES_CO from . import lang_VN from . import lang_TR +from . import lang_UK CONVERTER_CLASSES = { @@ -64,7 +65,8 @@ CONVERTER_CLASSES = { 'he': lang_HE.Num2Word_HE(), 'it': lang_IT.Num2Word_IT(), 'vi_VN': lang_VN.Num2Word_VN(), - 'tr': lang_TR.Num2Word_TR() + 'tr': lang_TR.Num2Word_TR(), + 'uk': lang_UK.Num2Word_UK() } def num2words(number, ordinal=False, lang='en'): From 1d580f1be7974889077eb245a01ee3f3ac2f4ede Mon Sep 17 00:00:00 2001 From: Sergio Zholudov Date: Fri, 8 Sep 2017 17:47:42 +0300 Subject: [PATCH 87/99] Updated README.rst, added Ukrainian --- README.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/README.rst b/README.rst index 6eb5588..ee61dd6 100644 --- a/README.rst +++ b/README.rst @@ -70,6 +70,7 @@ cardinal one. * ``ru`` (Russian) * ``tr`` (Turkish) * ``vn`` (Vietnamese) +* ``uk`` (Ukrainian) You can supply values like ``fr_FR``, the code will be correctly interpreted. If you supply an unsupported language, ``NotImplementedError`` is raised. From 294d350fb9b5c44de7bbb6b2cd04670d2653440f Mon Sep 17 00:00:00 2001 From: Armin Date: Fri, 8 Sep 2017 17:42:30 +0200 Subject: [PATCH 88/99] added NL test cases --- num2words/lang_NL.py | 1 - tests/test_nl.py | 52 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 tests/test_nl.py diff --git a/num2words/lang_NL.py b/num2words/lang_NL.py index 2447f7e..a802fd6 100644 --- a/num2words/lang_NL.py +++ b/num2words/lang_NL.py @@ -141,7 +141,6 @@ def main(): -21212121211221211111, -2.121212, -1.0000100]: n2w.test(val) - # n2w.test(1325325436067876801768700107601001012212132143210473207540327057320957032975032975093275093275093270957329057320975093272950730) n2w.test(3000000) n2w.test(3000000000001) n2w.test(3000000324566) diff --git a/tests/test_nl.py b/tests/test_nl.py new file mode 100644 index 0000000..e7a71f4 --- /dev/null +++ b/tests/test_nl.py @@ -0,0 +1,52 @@ +# -*- encoding: utf-8 -*- +# Copyright (c) 2015, 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 unittest import TestCase + +from num2words import num2words + +class Num2WordsNLTest(TestCase): + def test_ordinal_less_than_twenty(self): + self.assertEqual(num2words(7, ordinal=True, lang='nl'), "zevende") + self.assertEqual(num2words(8, ordinal=True, lang='nl'), "achtste") + self.assertEqual(num2words(12, ordinal=True, lang='nl'), "twaalfde") + self.assertEqual(num2words(17, ordinal=True, lang='nl'), "zeventiende") + + def test_ordinal_more_than_twenty(self): + self.assertEqual(num2words(81, ordinal=True, lang='nl'), "eenentachtigste") + + def test_ordinal_at_crucial_number(self): + self.assertEqual(num2words(100, ordinal=True, lang='nl'), "honderdste") + self.assertEqual(num2words(1000, ordinal=True, lang='nl'), "duizendste") + self.assertEqual(num2words(4000, ordinal=True, lang='nl'), "vierduizendste") + self.assertEqual(num2words(2000000, ordinal=True, lang='nl'), "twee miljoenste") + self.assertEqual(num2words(5000000000, ordinal=True, lang='nl'), "vijf miljardste") + + def test_cardinal_at_some_numbers(self): + self.assertEqual(num2words(1013, lang='nl'), "duizenddertien") + self.assertEqual(num2words(2000000, lang='nl'), "twee miljoen") + self.assertEqual(num2words(4000000000, lang='nl'), "vier miljard") + + def test_cardinal_for_decimal_number(self): + self.assertEqual(num2words(3.486, lang='nl'), "drie komma vier acht zes") + + def test_ordinal_for_negative_numbers(self): + self.assertRaises(TypeError, num2words, -12, ordinal=True, lang='nl') + + def test_ordinal_for_floating_numbers(self): + self.assertRaises(TypeError, num2words, 2.453, ordinal=True, lang='nl') \ No newline at end of file From 63fe589b98f4d56a5803623736d9766b1f6ce08f Mon Sep 17 00:00:00 2001 From: Armin Date: Fri, 8 Sep 2017 17:47:23 +0200 Subject: [PATCH 89/99] fixed test bug --- tests/test_nl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_nl.py b/tests/test_nl.py index e7a71f4..7a32147 100644 --- a/tests/test_nl.py +++ b/tests/test_nl.py @@ -43,7 +43,7 @@ class Num2WordsNLTest(TestCase): self.assertEqual(num2words(4000000000, lang='nl'), "vier miljard") def test_cardinal_for_decimal_number(self): - self.assertEqual(num2words(3.486, lang='nl'), "drie komma vier acht zes") + self.assertEqual(num2words(3.486, lang='nl'), "drie komma vier acht") def test_ordinal_for_negative_numbers(self): self.assertRaises(TypeError, num2words, -12, ordinal=True, lang='nl') From 7fe315eb640f0651711ca927a00f2941a6fd5782 Mon Sep 17 00:00:00 2001 From: Armin Date: Fri, 8 Sep 2017 17:54:25 +0200 Subject: [PATCH 90/99] fixed bug with 12 and 11 --- num2words/lang_NL.py | 4 ++-- tests/test_nl.py | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/num2words/lang_NL.py b/num2words/lang_NL.py index a802fd6..5bbaa0a 100644 --- a/num2words/lang_NL.py +++ b/num2words/lang_NL.py @@ -65,8 +65,8 @@ class Num2Word_NL(Num2Word_EU): "acht": "achtst", "negen": "negend", "tien":"tiend", - "elf":"elfde", - "twaalf":"twaalfde", + "elf":"elfd", + "twaalf":"twaalfd", "ig": "igst", "erd": "erdst", diff --git a/tests/test_nl.py b/tests/test_nl.py index 7a32147..70edebc 100644 --- a/tests/test_nl.py +++ b/tests/test_nl.py @@ -38,6 +38,7 @@ class Num2WordsNLTest(TestCase): self.assertEqual(num2words(5000000000, ordinal=True, lang='nl'), "vijf miljardste") def test_cardinal_at_some_numbers(self): + self.assertEqual(num2words(82, lang='nl'), u'twee\xebntachtig') self.assertEqual(num2words(1013, lang='nl'), "duizenddertien") self.assertEqual(num2words(2000000, lang='nl'), "twee miljoen") self.assertEqual(num2words(4000000000, lang='nl'), "vier miljard") From 4b58b1ee25947a6fd2b0812e747ec6be4f5c0ec2 Mon Sep 17 00:00:00 2001 From: Armin Date: Fri, 8 Sep 2017 19:29:37 +0200 Subject: [PATCH 91/99] updated readme --- README.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 813e87f..eb944d7 100644 --- a/README.rst +++ b/README.rst @@ -6,7 +6,7 @@ num2words - Convert numbers to words in multiple languages ``num2words`` is a library that converts numbers like ``42`` to words like ``forty-two``. It supports multiple languages (English, Arabic, Danish, French, -German, Hebrew, Italian, Latvian, Norwegian, Polish, Portuguese, Russian, +German, Dutch, Hebrew, Italian, Latvian, Norwegian, Polish, Portuguese, Russian, Spanish and Lithuanian) and can even generate ordinal numbers like ``forty-second`` (altough this last feature is a bit buggy at the moment). @@ -65,6 +65,8 @@ cardinal one. * ``pl`` (Polish) * ``pt_BR`` (Brazilian Portuguese) * ``ru`` (Russian) +* ``nl`` (Dutch) + You can supply values like ``fr_FR``, the code will be correctly interpreted. If you supply an unsupported language, ``NotImplementedError`` is raised. From 90b85a366cdc827949a5b3ac3a3fd4ef3e818fc5 Mon Sep 17 00:00:00 2001 From: Sergio Zholudov Date: Mon, 11 Sep 2017 12:43:30 +0300 Subject: [PATCH 92/99] Tests Ukrainian language --- tests/test_uk.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 tests/test_uk.py diff --git a/tests/test_uk.py b/tests/test_uk.py new file mode 100644 index 0000000..e5523fb --- /dev/null +++ b/tests/test_uk.py @@ -0,0 +1,28 @@ +# 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 unittest import TestCase + +from num2words import num2words + +class Num2WordsENTest(TestCase): + def test_and_join_199(self): + self.assertEqual(num2words(187), "сто вісімдесят сім") + + def test_cardinal_for_float_number(self): + self.assertEqual(num2words(12.40), "дванадцять кома сорок") + self.assertEqual(num2words(17.31), "сімнадцять кома тридцять один") + self.assertEqual(num2words(14.13), "чотирнадцять кома тринадцять") + self.assertEqual(num2words(12.31), "дванадцять кома тридцять один") From 279b63ed50da15f0d6ba6027d023c0d8373adda2 Mon Sep 17 00:00:00 2001 From: Sergio Zholudov Date: Mon, 11 Sep 2017 13:01:59 +0300 Subject: [PATCH 93/99] update test_uk --- tests/test_uk.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/test_uk.py b/tests/test_uk.py index e5523fb..0dff2aa 100644 --- a/tests/test_uk.py +++ b/tests/test_uk.py @@ -19,10 +19,10 @@ from num2words import num2words class Num2WordsENTest(TestCase): def test_and_join_199(self): - self.assertEqual(num2words(187), "сто вісімдесят сім") + self.assertEqual(num2words(187,lang='uk'), "сто вісімдесят сім") def test_cardinal_for_float_number(self): - self.assertEqual(num2words(12.40), "дванадцять кома сорок") - self.assertEqual(num2words(17.31), "сімнадцять кома тридцять один") - self.assertEqual(num2words(14.13), "чотирнадцять кома тринадцять") - self.assertEqual(num2words(12.31), "дванадцять кома тридцять один") + self.assertEqual(num2words(12.40,lang='uk'), "дванадцять кома сорок") + self.assertEqual(num2words(17.31,lang='uk'), "сімнадцять кома тридцять один") + self.assertEqual(num2words(14.13,lang='uk'), "чотирнадцять кома тринадцять") + self.assertEqual(num2words(12.31,lang='uk'), "дванадцять кома тридцять один") From b93c71659752437b44787bbbae8a0d7b682a5793 Mon Sep 17 00:00:00 2001 From: Sergio Zholudov Date: Mon, 11 Sep 2017 13:38:00 +0300 Subject: [PATCH 94/99] update test_uk --- tests/test_uk.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_uk.py b/tests/test_uk.py index 0dff2aa..62a65fb 100644 --- a/tests/test_uk.py +++ b/tests/test_uk.py @@ -19,10 +19,10 @@ from num2words import num2words class Num2WordsENTest(TestCase): def test_and_join_199(self): - self.assertEqual(num2words(187,lang='uk'), "сто вісімдесят сім") + self.assertEqual(num2words(187,lang='uk'), "сто вiсiмдесят сiм") def test_cardinal_for_float_number(self): - self.assertEqual(num2words(12.40,lang='uk'), "дванадцять кома сорок") - self.assertEqual(num2words(17.31,lang='uk'), "сімнадцять кома тридцять один") + self.assertEqual(num2words(12.40,lang='uk'), "дванадцять кома чотири") + self.assertEqual(num2words(17.31,lang='uk'), "сiмнадцять кома тридцять один") self.assertEqual(num2words(14.13,lang='uk'), "чотирнадцять кома тринадцять") self.assertEqual(num2words(12.31,lang='uk'), "дванадцять кома тридцять один") From 88eb77c92710f7d26f1c89698f75c0d0d0adccab Mon Sep 17 00:00:00 2001 From: Sergio Zholudov Date: Mon, 11 Sep 2017 13:40:56 +0300 Subject: [PATCH 95/99] update test_uk.py --- tests/test_uk.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_uk.py b/tests/test_uk.py index 62a65fb..b45d9b3 100644 --- a/tests/test_uk.py +++ b/tests/test_uk.py @@ -23,6 +23,6 @@ class Num2WordsENTest(TestCase): def test_cardinal_for_float_number(self): self.assertEqual(num2words(12.40,lang='uk'), "дванадцять кома чотири") - self.assertEqual(num2words(17.31,lang='uk'), "сiмнадцять кома тридцять один") + self.assertEqual(num2words(17.31,lang='uk'), "сiмнадцять кома тридцять одна") self.assertEqual(num2words(14.13,lang='uk'), "чотирнадцять кома тринадцять") - self.assertEqual(num2words(12.31,lang='uk'), "дванадцять кома тридцять один") + self.assertEqual(num2words(12.31,lang='uk'), "дванадцять кома тридцять одна") From 71419ffa0e4648e33c4856fc4ac525b87b4adf80 Mon Sep 17 00:00:00 2001 From: Sergio Zholudov Date: Mon, 11 Sep 2017 13:43:39 +0300 Subject: [PATCH 96/99] update lang_uk.py --- num2words/lang_UK.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/num2words/lang_UK.py b/num2words/lang_UK.py index 14d04b6..06d7c79 100644 --- a/num2words/lang_UK.py +++ b/num2words/lang_UK.py @@ -112,8 +112,8 @@ ONES_FEMININE = { 4: (u'чотири',), 5: (u'п\'ять',), 6: (u'шiсть',), - 7: (u'сiмь',), - 8: (u'вiсiмь',), + 7: (u'сiм',), + 8: (u'вiсiм',), 9: (u'дев\'ять',), } From 865a311437f8a320b8f6f21399f0c38d7f00c61c Mon Sep 17 00:00:00 2001 From: Sergio Zholudov Date: Mon, 11 Sep 2017 13:48:18 +0300 Subject: [PATCH 97/99] Ukrainian language test update --- tests/test_uk.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_uk.py b/tests/test_uk.py index b45d9b3..fc5b669 100644 --- a/tests/test_uk.py +++ b/tests/test_uk.py @@ -17,7 +17,7 @@ from unittest import TestCase from num2words import num2words -class Num2WordsENTest(TestCase): +class Num2WordsUKTest(TestCase): def test_and_join_199(self): self.assertEqual(num2words(187,lang='uk'), "сто вiсiмдесят сiм") From 23b1961fe53602aeaa6dac28483cd189892e1131 Mon Sep 17 00:00:00 2001 From: Sergio Zholudov Date: Mon, 11 Sep 2017 14:32:16 +0300 Subject: [PATCH 98/99] updated test_uk --- tests/test_uk.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_uk.py b/tests/test_uk.py index fc5b669..5ddc7a4 100644 --- a/tests/test_uk.py +++ b/tests/test_uk.py @@ -1,3 +1,4 @@ +# -*- encoding: utf-8 -*- # Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. # This library is free software; you can redistribute it and/or From 28f3d3bcff7077c7e45b37ef3211a61d02a2d72a Mon Sep 17 00:00:00 2001 From: Sergio Zholudov Date: Mon, 11 Sep 2017 15:05:11 +0300 Subject: [PATCH 99/99] update uk_test (utf-8 issue resolved) --- tests/test_uk.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/test_uk.py b/tests/test_uk.py index 5ddc7a4..26760ae 100644 --- a/tests/test_uk.py +++ b/tests/test_uk.py @@ -20,10 +20,10 @@ from num2words import num2words class Num2WordsUKTest(TestCase): def test_and_join_199(self): - self.assertEqual(num2words(187,lang='uk'), "сто вiсiмдесят сiм") + self.assertEqual(num2words(187,lang='uk'), u"сто вiсiмдесят сiм") def test_cardinal_for_float_number(self): - self.assertEqual(num2words(12.40,lang='uk'), "дванадцять кома чотири") - self.assertEqual(num2words(17.31,lang='uk'), "сiмнадцять кома тридцять одна") - self.assertEqual(num2words(14.13,lang='uk'), "чотирнадцять кома тринадцять") - self.assertEqual(num2words(12.31,lang='uk'), "дванадцять кома тридцять одна") + self.assertEqual(num2words(12.40,lang='uk'), u"дванадцять кома чотири") + self.assertEqual(num2words(17.31,lang='uk'), u"сiмнадцять кома тридцять одна") + self.assertEqual(num2words(14.13,lang='uk'), u"чотирнадцять кома тринадцять") + self.assertEqual(num2words(12.31,lang='uk'), u"дванадцять кома тридцять одна")