235 lines
8.1 KiB
Python
235 lines
8.1 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Copyright (c) 2003, Taro Ogawa. All Rights Reserved.
|
|
# Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved.
|
|
|
|
# This library is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU Lesser General Public
|
|
# License as published by the Free Software Foundation; either
|
|
# version 2.1 of the License, or (at your option) any later version.
|
|
# This library is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
# Lesser General Public License for more details.
|
|
# You should have received a copy of the GNU Lesser General Public
|
|
# License along with this library; if not, write to the Free Software
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
# MA 02110-1301 USA
|
|
|
|
from __future__ import unicode_literals
|
|
|
|
from .base import Num2Word_Base
|
|
from .utils import get_digits, splitbyx
|
|
|
|
ZERO = ('ноль',)
|
|
|
|
ONES_FEMININE = {
|
|
1: ('одна',),
|
|
2: ('две',),
|
|
3: ('три',),
|
|
4: ('четыре',),
|
|
5: ('пять',),
|
|
6: ('шесть',),
|
|
7: ('семь',),
|
|
8: ('восемь',),
|
|
9: ('девять',),
|
|
}
|
|
|
|
ONES = {
|
|
1: ('один',),
|
|
2: ('два',),
|
|
3: ('три',),
|
|
4: ('четыре',),
|
|
5: ('пять',),
|
|
6: ('шесть',),
|
|
7: ('семь',),
|
|
8: ('восемь',),
|
|
9: ('девять',),
|
|
}
|
|
|
|
TENS = {
|
|
0: ('десять',),
|
|
1: ('одиннадцать',),
|
|
2: ('двенадцать',),
|
|
3: ('тринадцать',),
|
|
4: ('четырнадцать',),
|
|
5: ('пятнадцать',),
|
|
6: ('шестнадцать',),
|
|
7: ('семнадцать',),
|
|
8: ('восемнадцать',),
|
|
9: ('девятнадцать',),
|
|
}
|
|
|
|
TWENTIES = {
|
|
2: ('двадцать',),
|
|
3: ('тридцать',),
|
|
4: ('сорок',),
|
|
5: ('пятьдесят',),
|
|
6: ('шестьдесят',),
|
|
7: ('семьдесят',),
|
|
8: ('восемьдесят',),
|
|
9: ('девяносто',),
|
|
}
|
|
|
|
HUNDREDS = {
|
|
1: ('сто',),
|
|
2: ('двести',),
|
|
3: ('триста',),
|
|
4: ('четыреста',),
|
|
5: ('пятьсот',),
|
|
6: ('шестьсот',),
|
|
7: ('семьсот',),
|
|
8: ('восемьсот',),
|
|
9: ('девятьсот',),
|
|
}
|
|
|
|
THOUSANDS = {
|
|
1: ('тысяча', 'тысячи', 'тысяч'), # 10^3
|
|
2: ('миллион', 'миллиона', 'миллионов'), # 10^6
|
|
3: ('миллиард', 'миллиарда', 'миллиардов'), # 10^9
|
|
4: ('триллион', 'триллиона', 'триллионов'), # 10^12
|
|
5: ('квадриллион', 'квадриллиона', 'квадриллионов'), # 10^15
|
|
6: ('квинтиллион', 'квинтиллиона', 'квинтиллионов'), # 10^18
|
|
7: ('секстиллион', 'секстиллиона', 'секстиллионов'), # 10^21
|
|
8: ('септиллион', 'септиллиона', 'септиллионов'), # 10^24
|
|
9: ('октиллион', 'октиллиона', 'октиллионов'), # 10^27
|
|
10: ('нониллион', 'нониллиона', 'нониллионов'), # 10^30
|
|
}
|
|
|
|
|
|
class Num2Word_RU(Num2Word_Base):
|
|
CURRENCY_FORMS = {
|
|
'RUB': (
|
|
('рубль', 'рубля', 'рублей'), ('копейка', 'копейки', 'копеек')
|
|
),
|
|
'EUR': (
|
|
('евро', 'евро', 'евро'), ('цент', 'цента', 'центов')
|
|
),
|
|
'USD': (
|
|
('доллар', 'доллара', 'долларов'), ('цент', 'цента', 'центов')
|
|
),
|
|
}
|
|
|
|
def setup(self):
|
|
self.negword = "минус"
|
|
self.pointword = "запятая"
|
|
self.ords = {"ноль": "нулевой",
|
|
"один": "первый",
|
|
"два": "второй",
|
|
"три": "третий",
|
|
"четыре": "четвертый",
|
|
"пять": "пятый",
|
|
"шесть": "шестой",
|
|
"семь": "седьмой",
|
|
"восемь": "восьмой",
|
|
"девять": "девятый",
|
|
"сто": "сотый"}
|
|
self.ords_feminine = {"один": "",
|
|
"одна": "",
|
|
"две": "двух",
|
|
"три": "трёх",
|
|
"четыре": "четырёх",
|
|
"пять": "пяти",
|
|
"шесть": "шести",
|
|
"семь": "семи",
|
|
"восемь": "восьми",
|
|
"девять": "девяти"}
|
|
|
|
def to_cardinal(self, number):
|
|
n = str(number).replace(',', '.')
|
|
if '.' in n:
|
|
left, right = n.split('.')
|
|
return u'%s %s %s' % (
|
|
self._int2word(int(left)),
|
|
self.pointword,
|
|
self._int2word(int(right))
|
|
)
|
|
else:
|
|
return self._int2word(int(n))
|
|
|
|
def pluralize(self, n, forms):
|
|
if n % 100 < 10 or n % 100 > 20:
|
|
if n % 10 == 1:
|
|
form = 0
|
|
elif 5 > n % 10 > 1:
|
|
form = 1
|
|
else:
|
|
form = 2
|
|
else:
|
|
form = 2
|
|
return forms[form]
|
|
|
|
def to_ordinal(self, number):
|
|
self.verify_ordinal(number)
|
|
outwords = self.to_cardinal(number).split(" ")
|
|
lastword = outwords[-1].lower()
|
|
try:
|
|
if len(outwords) > 1:
|
|
if outwords[-2] in self.ords_feminine:
|
|
outwords[-2] = self.ords_feminine.get(
|
|
outwords[-2], outwords[-2])
|
|
elif outwords[-2] == 'десять':
|
|
outwords[-2] = outwords[-2][:-1] + 'и'
|
|
if len(outwords) == 3:
|
|
if outwords[-3] in ['один', 'одна']:
|
|
outwords[-3] = ''
|
|
lastword = self.ords[lastword]
|
|
except KeyError:
|
|
if lastword[:-3] in self.ords_feminine:
|
|
lastword = self.ords_feminine.get(
|
|
lastword[:-3], lastword) + "сотый"
|
|
elif lastword[-1] == "ь" or lastword[-2] == "т":
|
|
lastword = lastword[:-1] + "ый"
|
|
elif lastword[-1] == "к":
|
|
lastword = lastword + "овой"
|
|
elif lastword[-5:] == "десят":
|
|
lastword = lastword.replace('ь', 'и') + 'ый'
|
|
elif lastword[-2] == "ч" or lastword[-1] == "ч":
|
|
if lastword[-2] == "ч":
|
|
lastword = lastword[:-1] + "ный"
|
|
if lastword[-1] == "ч":
|
|
lastword = lastword + "ный"
|
|
elif lastword[-1] == "н" or lastword[-2] == "н":
|
|
lastword = lastword[:lastword.rfind('н') + 1] + "ный"
|
|
elif lastword[-1] == "д" or lastword[-2] == "д":
|
|
lastword = lastword[:lastword.rfind('д') + 1] + "ный"
|
|
outwords[-1] = self.title(lastword)
|
|
return " ".join(outwords).strip()
|
|
|
|
def _cents_verbose(self, number, currency):
|
|
return self._int2word(number, currency == 'RUB')
|
|
|
|
def _int2word(self, n, feminine=False):
|
|
if n < 0:
|
|
return ' '.join([self.negword, self._int2word(abs(n))])
|
|
|
|
if n == 0:
|
|
return ZERO[0]
|
|
|
|
words = []
|
|
chunks = list(splitbyx(str(n), 3))
|
|
i = len(chunks)
|
|
for x in chunks:
|
|
i -= 1
|
|
|
|
if x == 0:
|
|
continue
|
|
|
|
n1, n2, n3 = get_digits(x)
|
|
|
|
if n3 > 0:
|
|
words.append(HUNDREDS[n3][0])
|
|
|
|
if n2 > 1:
|
|
words.append(TWENTIES[n2][0])
|
|
|
|
if n2 == 1:
|
|
words.append(TENS[n1][0])
|
|
elif n1 > 0:
|
|
ones = ONES_FEMININE if i == 1 or feminine and i == 0 else ONES
|
|
words.append(ones[n1][0])
|
|
|
|
if i > 0:
|
|
words.append(self.pluralize(x, THOUSANDS[i]))
|
|
|
|
return ' '.join(words)
|