0

While starting to learn Python, I found a problem when trying to program a calculation using split. If I were to have whitespaces in my string

15 - 3

then the program runs fine.

If I didn't have whitespaces in my string

15-3

then I get an error message because split expected 3 values (the two values and the operator). I tried to compensate for it by using this:

num1, operator, num2 = input("Enter calculation: ").split()

if not num1.isdigit() or not num2.isdigit():
    print("Please use whitespaces in calculation")
else:
    num1 = int(num1)
    num2 = int(num2)
    if operator == "+":
        print("{} + {} = {}".format(num1, num2, num1+num2))
    elif...

However, this still doesn't catch the error if I don't use whitespaces. What am I doing wrong?

too honest for this site
  • 12,050
  • 4
  • 30
  • 52
Barry Hammer
  • 183
  • 6
  • I am using it as a conditional, to catch IF I have a whiltespace or not in the value. So yes, i am asking why it doesn't work. – Barry Hammer Feb 13 '18 at 10:21
  • What part of this code you expect to "compensate" for no whitespaces? – DeepSpace Feb 13 '18 at 10:21
  • The exact first thing you do is trying to parse `num1` `operator` and `num2` based on a whitespace split of the input. (see first line `.split()`). Based on this, you can not ever handle the case where there is no space. – arnaud Feb 13 '18 at 10:21
  • My thinking was that if there is no whitespace, the first if statement should catch it, since num1 or num2 would not be a digit but would have an operator as part of the value – Barry Hammer Feb 13 '18 at 10:22
  • No, in the case there is no whitespace then the first line already behaves wrongly for you, and num1 num2 and operator are wrongly parsed. – arnaud Feb 13 '18 at 10:23

5 Answers5

4

The split separates the string on spaces (by default) so if the user doesn't enter any, then the string is split into just one part and can't be unpacked into your variables.

I would handle this by either using a try...except, or by storing the whole input first and using the count method to check the user has actually entered the two spaces required:

inp = input("Enter calculation: ")
if inp.count(" ") < 2:
    print("Please use whitespaces in calculation")
else:
    num1, operator, num2 = inp.split()
    ...
Joe Iddon
  • 20,101
  • 7
  • 33
  • 54
  • Thanks, this would make the most sense. Theoretically, I can still throw an error by being a dummy and using multiple whitespaces in the wrong places (like using multiple whitespace between the first value and the operator, and leaving no whitespace between the operator and the second value), but this would be the best option for others also beginning to learn to code. Much obliged! – Barry Hammer Feb 13 '18 at 10:31
1

The split line can raise a ValueError: not enough values to unpack... and as a result, your if checks are never executed (and they are sub-optimal too btw).

num1, operator, num2 = input("Enter calculation: ").split()

As a result, you have 2 options:

  1. Check the passed string before splitting it:

    user_calc = input("Enter calculation: ")
    if ' ' not in user_calc:
        # do something about it
    
  2. or wrap the thing in a try-except block:

    try:
        num1, operator, num2 = input("Enter calculation: ").split()
    except ValueError:
        # do something about it
    

Now it seems to me that regardless of which option you choose you would have to wrap it in a while to give the user the ability to correct his input without having to run the code again. For a detailed description of how to do that, look at this excellent post


Note that option 1. in your case is not optimal though, because if a user passes e.g., 15 -2, the if will not trigger and the ValueError raised.


So to sum up, I would do it like this:

while True:
    try:
        num1, operator, num2 = input("Enter calculation: ").split()
    except ValueError:
        print('Spaces are needed between characters!')
    else:
        break
# rest of your code
Ma0
  • 15,057
  • 4
  • 35
  • 65
  • Option `1` wouldn't work in the case where they entered `"5 +6"` (not sure why someone would but it's good to be complete! – Joe Iddon Feb 13 '18 at 10:25
  • @JoeIddon I was adding this comment to the answer. Simply trying to answer in a general way. – Ma0 Feb 13 '18 at 10:27
  • Yeah, I figured that would be the case, and indeed just tried it. I need to make sure there is a whitespace between the values and the operators, not just one whitespace. But thanks for the answer. – Barry Hammer Feb 13 '18 at 10:28
0

Here's an idea:

import ast

str_input = input("Enter calculation: ")

print(ast.literal_eval(str_input))
jpp
  • 159,742
  • 34
  • 281
  • 339
0

You can also use regex and forget about spaces

import re

num1, operator, num2 = re.split("([+-/*])", input("Enter calculation: ").replace(" ", ""))

print(eval(num1 + operator + num2))
Maharramoff
  • 941
  • 8
  • 15
  • 1
    A bit complex for a beginner, but thanks for the answer. – Barry Hammer Feb 13 '18 at 10:34
  • This would hide input errors such as `1 5 - 3` because *all* spaces are discarded. Better adjust the regex to work with *or* without spaces around the operator. – Jongware Feb 13 '18 at 10:54
0

Otherwise, you could just want to prevent any spacing from altering your input. That is, remove all spaces from the string and then split() on the operator using re.

import re 
inp = input("Enter calculation: ")  # collect input operation from user
inp = "".join(inp.split())  # remove all whitespaces
num1, operator, num2 = re.split("([+-/*])", inp)  # split based on any operator in ['+', '-', '*', '/']

In that case, you can parse any tricky case like :
* 1+ 12
* 2-5
* 1 * 5

arnaud
  • 3,293
  • 1
  • 10
  • 27