0

How to limit input to only integers or numbers with two decimal places, else (alphabet or other symbols) it will display 'invalid' and allow the user to enter again.

code:

counter = 100
income = input("Enter income: ")

while counter >0:
    try:
       val = int(income)
       print ("YES")
       income = input("Enter money: ")
       counter = counter - 1
    except ValueError:
       print("NO")
       income = input("Enter money: ")
       counter = counter - 1

I've taken the val = int (???) from another question and it works if it's limiting to integer input only, since my program involves money I need it to go up to two decimal places but it does not accept decimals. (The counter are only for me to test the program)

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • Should the money amount be stored as cents/pence? It is not a good idea to store money amounts as float. – cdarke May 04 '15 at 16:10
  • 1
    [It's a much better idea to use Decimal](http://stackoverflow.com/a/1406800/344286) or something to that effect. – Wayne Werner May 04 '15 at 17:13

4 Answers4

1

You could define your own input function

def input_number(msg):
    while True:
        try:
            res = round(float(input(msg)), 2)
            break
        except:
            print("Invalid")
    return res

income = input_number("Enter money:\n")
1

You could use regexp :

import re
is_number=re.compile('^\d+\.?\d{,2}$')

>>>is_number.match('3.14') is not None
True
>>>is_number.match('32222') is not None
True
>>> is_number.match('32A') is not None
False
>>> is_number.match('3.1445') is not None
False
manu190466
  • 1,557
  • 1
  • 9
  • 17
1

In my opinion you need a regular expression for the features you need, in particular ensuring exactly two digits after the decimal point, while making that optional.

I have imposed the income as pence or cents. This is because you may get rounding issues using float.

import re

# income as pence/cents
income = None

while income is None:
    instr = input("Enter money: ")
    m = re.fullmatch(r'(\d+)(?:\.(\d{2}))?', instr)
    if m:
        full, cents =  m.groups()
        if cents == '' or cents is None: 
            cents = '0'
        income = (int(full) * 100) + int(cents)
    else:
        print("NO")

print("Income is %d.%02d" % (income/100, income % 100))
cdarke
  • 42,728
  • 8
  • 80
  • 84
1

With this many constraints on the pattern, I really think a regex is more declarative and readable.

import re 
NUM_REGEX = re.compile(r"^\d+(?:\.\d{,2})?$")

input_str = input("give me a number") 

while NUM_REGEX.match(input_str) is None:
    input_str = input("Nope, not valid. Give me another.")

return float(input_str) 
jwilner
  • 6,348
  • 6
  • 35
  • 47