Convert an amount to Indian Notation in Python
Asked Answered
P

11

15

Problem: I need to convert an amount to Indian currency format

My code: I have the following Python implementation:

import decimal
def currencyInIndiaFormat(n):
  d = decimal.Decimal(str(n))
  if d.as_tuple().exponent < -2:
    s = str(n)
  else:
    s = '{0:.2f}'.format(n)
  l = len(s)
  i = l-1;
  res = ''
  flag = 0
  k = 0
  while i>=0:
    if flag==0:
      res = res + s[i]
      if s[i]=='.':
        flag = 1
    elif flag==1:
      k = k + 1
      res = res + s[i]
      if k==3 and i-1>=0:
        res = res + ','
        flag = 2
        k = 0
    else:
      k = k + 1
      res = res + s[i]
      if k==2 and i-1>=0:
        res = res + ','
        flag = 2
        k = 0
    i = i - 1

  return res[::-1]

def main():
  n = 100.52
  print "INR " + currencyInIndiaFormat(n)  # INR 100.52
  n = 1000.108
  print "INR " + currencyInIndiaFormat(n)  # INR 1,000.108
  n = 1200000
  print "INR " + currencyInIndiaFormat(n)  # INR 12,00,000.00

main()

My Question: Is there a way to make my currencyInIndiaFormat function shorter, more concise and clean ? / Is there a better way to write my currencyInIndiaFormat function ?

Note: My question is mainly based on Python implementation of the above stated problem. It is not a duplicate of previously asked questions regarding conversion of currency to Indian format.

Indian Currency Format:

For example, numbers here are represented as:

1
10
100
1,000
10,000
1,00,000
10,00,000
1,00,00,000
10,00,00,000

Refer Indian Numbering System

Proteiform answered 3/12, 2016 at 19:19 Comment(3)
Can you enlighten us about the Indian currency format?Fusionism
There's a lot of single variable names in there. Making those more descriptive would be the easiest win. Also, this should be on Code Review.Electromagnet
@DYZ: Added Indian currency format!!!Proteiform
M
29

Too much work.

>>> import locale
>>> locale.setlocale(locale.LC_MONETARY, 'en_IN')
'en_IN'
>>> print(locale.currency(100.52, grouping=True))
₹ 100.52
>>> print(locale.currency(1000.108, grouping=True))
₹ 1,000.11
>>> print(locale.currency(1200000, grouping=True))
₹ 12,00,000.00
Multivibrator answered 3/12, 2016 at 21:20 Comment(6)
Doesn't work for me,I get following message Error: unsupported locale settingCherriecherrita
Then install the locale, or use a similar one.Multivibrator
Can't seem to install locales on OSX, apparently.Baler
This work., However you need to configure locale in your local machine a swell. Just type locale in your terminal shell in linux.. If the used locale is not present in local machine. It will throw the error.Biebel
How do we install en_IN locale on macOS Mojave ?Rabia
Thou it is working but only issue I can see is currency symbol is showing ?.Nunnally
J
18

Simple version:

def formatINR(number):
    s, *d = str(number).partition(".")
    r = ",".join([s[x-2:x] for x in range(-3, -len(s), -2)][::-1] + [s[-3:]])
    return "".join([r] + d)

Sample:

print(formatINR(123456))

Output:

1,23,456

If you want to handle negative numbers and strings,

def formatINR(number):
    number = float(number)
    number = round(number,2)
    is_negative = number < 0
    number = abs(number)
    s, *d = str(number).partition(".")
    r = ",".join([s[x-2:x] for x in range(-3, -len(s), -2)][::-1] + [s[-3:]])
    value = "".join([r] + d)
    if is_negative:
       value = '-' + value
    return '₹'+ value

Sample:

print(formatINR('-004.256'))

Output:

₹-4.26
Jacquelynnjacquenetta answered 22/7, 2021 at 12:1 Comment(3)
Why is this not upvoted more ? It's the simplest solution!Flay
The easiest one here. Thanks!Accessary
@Flay not production level, has few case where it fails, it only assume that passing function parameter is decimal or integer only, in case it is string having 0000 in starting of it it wont remove them and will show unwanted result, so whoever is using this function just check the number you are passingKalahari
F
15

You can follow these steps. Install Babel python package from pip

pip install Babel

In your python script

from babel.numbers import format_currency
format_currency(5433422.8012, 'INR', locale='en_IN')

Output:

₹ 54,33,422.80
Freemanfreemartin answered 12/10, 2018 at 14:12 Comment(1)
This one provide correct output but quite slower than locale.Nunnally
F
3

Note - THIS IS AN ALTERNATIVE SOLUTION FOR ACTUAL QUESTION

If anyone trying to convert in simple Indian terms like K, L, or Cr with 2 floating-point values, the following solution would work.

def format_cash(amount):
    def truncate_float(number, places):
        return int(number * (10 ** places)) / 10 ** places

    if amount < 1e3:
        return amount

    if 1e3 <= amount < 1e5:
        return str(truncate_float((amount / 1e5) * 100, 2)) + " K"

    if 1e5 <= amount < 1e7:
        return str(truncate_float((amount / 1e7) * 100, 2)) + " L"

    if amount > 1e7:
        return str(truncate_float(amount / 1e7, 2)) + " Cr"

Examples

format_cash(7843) --> '7.84 K'
format_cash(78436) --> '78.43 K'
format_cash(784367) --> '7.84 L'
format_cash(7843678) --> '78.43 L'
format_cash(78436789) --> '7.84 Cr'
Fricke answered 21/12, 2021 at 17:11 Comment(0)
C
1

Here is the other way around:

import re
def in_for(value):
    value,b=str(value),''
    value=''.join(map(lambda va:va if re.match(r'[0-9,.]',va) else '',value))
    val=value
    if val.count(',')==0:
        v,c,a,cc,ii=val,0,[3,2,2],0,0
        val=val[:val.rfind('.')] if val.rfind('.')>=0  else val
        for i in val[::-1]:
            if c==ii and c!=0:
                ii+=a[cc%3]
                b=','+i+b
                cc+=1  
            else:
                b=i+b
            c+=1
        b=b[1:] if b[0]==',' else b
        val=b+v[value.rfind('.'):]  if value.rfind('.')>=0  else b
    else:
        val=str(val).strip('()').replace(' ','')
    v=val.rfind('.')
    if v>0:
        val=val[:v+3]
    return val.rstrip('0').rstrip('.') if '.' in val else val

print(in_for('1000000000000.5445'))

Output will be:

10,000,00,00,000.54 

(As mentioned in wikipedia indian number system Ex:67,89,000,00,00,000)

Capture answered 24/5, 2019 at 9:32 Comment(0)
A
1
def format_indian(t):
dic = {
    4:'Thousand',
    5:'Lakh',
    6:'Lakh',
    7:'Crore',
    8:'Crore',
    9:'Arab'
}
y = 10
len_of_number = len(str(t))
save = t
z=y
while(t!=0):
   t=int(t/y)
   z*=10

zeros = len(str(z)) - 3
if zeros>3:
    if zeros%2!=0:
        string = str(save)+": "+str(save/(z/100))[0:4]+" "+dic[zeros]
    else:   
        string = str(save)+": "+str(save/(z/1000))[0:4]+" "+dic[zeros]
    return string
return str(save)+": "+str(save)

This code will Convert Yout Numbers to Lakhs, Crores and arabs in most simplest way. Hope it helps.

for i in [1.234567899 * 10**x for x in range(9)]:
print(format_indian(int(i)))

Output:

1: 1
12: 12
123: 123
1234: 1234
12345: 12.3 Thousand
123456: 1.23 Lakh
1234567: 12.3 Lakh
12345678: 1.23 Crore
123456789: 12.3 Crore
Ankylose answered 2/5, 2020 at 20:3 Comment(0)
W
1

As pgksunilkumar's answer, a little improvement is done in case the number is in between 0 to -1000

def formatINR(number):
    neg = False
    if number < 0:
        neg = True
    number = abs(number)
    s, *d = str(number).partition(".")
    r = ",".join([s[x-2:x] for x in range(-3, -len(s), -2)][::-1] + [s[-3:]])
    r = "-"+r if neg else r
    return "".join([r] + d)

now if the number is between 0 to -1000, the format will not disturb the user.

i.e

a = -600
b = -10000000
c = 700
d = 8000000
e = -30850

print(formatINR(a))
print(formatINR(b))
print(formatINR(c))
print(formatINR(d))
print(formatINR(e))

output will be:

-600
-1,00,00,000
700
80,00,000
-30,850
Worrywart answered 25/1, 2023 at 11:2 Comment(3)
Based on current definition also it won't disturb as per your use case alsoJacquelynnjacquenetta
But it shows in negative value start at "," . For example I pass the value "-33085.00" it return as -,33,085.0.Metamorphose
@GanesanJ Edited the Answer. You can pass any negative or positive value nowWorrywart
W
0

Another way:

def formatted_int(value):
    # if the value is 100, 10, 1

    if len(str(value)) <= 3:
        return value

    # if the value is 10,000, 1,000
    elif  3 < len(str(value)) <= 5:
        return f'{str(value)[:-3]},{str(value)[-3:]} ₹'

    # if the value is greater the 10,000    
    else:
        cut = str(value)[:-3]  
        o = []
        while cut:
            o.append(cut[-2:]) # appending from 1000th value(right to left)
            cut = cut[:-2]
        
        o = o[::-1] # reversing list
        res = ",".join(o) 
        
        return f'{res},{str(value)[-3:]} ₹'


value1 = 1_00_00_00_000
value2 = 10_00_00_00_000          
value3 = 100

print(formatted_int(value1))
print(formatted_int(value2))
print(formatted_int(value3))

Ouput:

    1,00,00,00,000 ₹

    10,00,00,00,000 ₹

    100 ₹        
Wards answered 3/6, 2021 at 15:18 Comment(1)
print(formatted_int(100-1000)) gives the output like -,900Worrywart
B
-1

Couldn't make the other two solutions work for me, so I made something a little more low-tech:

def format_as_indian(input):
    input_list = list(str(input))
    if len(input_list) <= 1:
        formatted_input = input
    else:
        first_number = input_list.pop(0)
        last_number = input_list.pop()
        formatted_input = first_number + (
            (''.join(l + ',' * (n % 2 == 1) for n, l in enumerate(reversed(input_list)))[::-1] + last_number)
        )

        if len(input_list) % 2 == 0:
            formatted_input.lstrip(',')

    return formatted_input

This doesn't work with decimals. If you need that, I would suggest saving the decimal portion into another variable and adding it back in at the end.

Baler answered 29/6, 2017 at 18:11 Comment(0)
G
-1
num=123456789
snum=str(num)
slen=len(snum)
result=''

if (slen-3)%2 !=0 :
    snum='x'+snum

for i in range(0,slen-3,2):
    result=result+snum[i:i+2]+','
    
result+=snum[slen-3:]
print(result.replace('x',''))


    
    
Gazo answered 20/6, 2021 at 11:38 Comment(3)
# Taking Input # Excluding last 3 digits.. %2 to verify remaing length of str is even or add..If even..Lite..Else..Add an extra character x in the begining # Iterate string(number) from 0 to len-3..By taking step count 2..Adding two two values to result set #finally combing both last 3 digits with result set which was just generatedGazo
Please don't post only code as answer, but also provide an explanation what your code does and how it solves the problem of the question. Answers with an explanation are usually more helpful and of better quality, and are more likely to attract upvotes.Kidnap
To expand on @Tyler2P's point, this is especially important here, where there are six other answers, including an accepted answer with quite a few upvotes from five years ago. What sets your answer apart? Why were the existing answers insufficient? Are you taking advantage of new syntax that wasn't available when the original answers were written? Help readers understand why they should consider your approach.Doublethink
F
-1

Those who needed it for Pandas float_format in Jupyter Notebook,

import locale
locale.setlocale(locale.LC_MONETARY, 'en_IN')

pd.options.display.float_format = lambda x : locale.currency(x, grouping=True)
Flirtation answered 22/2 at 13:57 Comment(1)
already discussed 6 years ago as the accepted answerFormative

© 2022 - 2024 — McMap. All rights reserved.