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 1/5] 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 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 2/5] 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 3/5] [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 4/5] 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 5/5] 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__":