The following code converts a number into Indian numbering system format.
I know locale can also help in getting similar format but I wanted something that can work on any system because not all locales are present in all OSs.
The code was written for Python 3.5 hence no variable annotations.
from decimal import Decimal
from itertools import islice, zip_longest
from typing import Any, Iterable, Iterator, Sequence, Tuple, TypeVar, Union # noqa: ignore=F401
_T = TypeVar('_T')
def grouper(iterable: Iterable[_T], n: int, fillvalue: Any = None) -> Iterator[Tuple[_T, ...]]:
"Collect data into fixed-length chunks or blocks"
# grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
args = [iter(iterable)] * n
return zip_longest(fillvalue=fillvalue, *args)
def indian_numbering_format(
amount: Union[Decimal, int, str], places: int = 2,
curr: str = '', pos: str = '', neg: str = '-'
) -> str:
"""
Formats a number and returns it in Indian numbering format
https://en.wikipedia.org/wiki/Indian_numbering_system
places: optional number of places after the decimal point
curr: optional currency symbol before the sign
pos: optional sign for positive numbers: '+' or blank
neg: optional sign for negative numbers: '-' or blank
Note that if the fractional part only contains 0 it will be
dropped.
"""
q = Decimal(10) ** -places # type: Decimal
amount = Decimal(amount).quantize(q)
sign, digits, exponent = amount.as_tuple()
integer_part, fractional_part = (), () # type: Sequence[int], Sequence[int]
exponent = exponent or len(digits)
integer_part = digits[:exponent]
# If fractional part only contains 0s then ignore it.
if set(digits[exponent:]) != {0}:
fractional_part = digits[exponent:]
integer_part_digits = reversed(''.join(map(str, integer_part)))
thousand = ''.join(islice(integer_part_digits, 3))[::-1]
hundreds = ','.join(map(''.join, grouper(integer_part_digits, 2, fillvalue='')))[::-1]
sep = ',' if hundreds else ''
fractional_part_digits = '.' + ''.join([str(d) for d in fractional_part]) if fractional_part else ''
return '{sign}{curr}{hundreds}{sep}{thousand}{fractional_part}'.format(
sign=neg if sign else pos,
curr=curr,
thousand=thousand,
sep=sep,
hundreds=hundreds,
fractional_part=fractional_part_digits
)
I was wondering if the code can be refactored in any way to make it much more simpler.