205 lines
6.3 KiB
Python
205 lines
6.3 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 print_function, unicode_literals
|
|
|
|
|
|
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 = "Number is too large to convert to words (abs(%s) > %s)."
|
|
MAXVAL = 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.MAXVAL:
|
|
raise OverflowError(self.errmsg_toobig % (number, self.MAXVAL))
|
|
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 == int(value):
|
|
raise TypeError(self.errmsg_floatord % value)
|
|
if not abs(value) == value:
|
|
raise TypeError(self.errmsg_negord % value)
|