So I'm creating a program to show number systems, however I've run into issues at the first hurdle. The program will take a number from the user and then use that number throughout the program in order to explain several computer science concepts.
When explaining my first section, number systems, the program will say what type of number it is. I'm doing this by converting the string into a float number. If the float number only has '.0' after it then it converts it into a integer.
Currently I'm using this code
while CorrectNumber == False:
try:
Number = float(NumberString) - 0
print (Number)
except:
print ("Error! Not a number!")
This is useful as it shows if the user has entered a number or not. However I am unsure how to now check the value after the decimal place to check if I should convert it into a integer or not. Any tips?
If the string is convertable to integer, it should be digits only. It should be noted that this approach, as #cwallenpoole said, does NOT work with negative inputs beacuse of the '-' character. You could do:
if NumberString.isdigit():
Number = int(NumberString)
else:
Number = float(NumberString)
If you already have Number confirmed as a float, you can always use is_integer (works with negatives):
if Number.is_integer():
Number = int(Number)
Not sure I follow the question but here is an idea:
test = ['1.1', '2.1', '3.0', '4', '5', '6.12']
for number in test:
try:
print(int(number))
except ValueError:
print(float(number))
Returns:
1.1
2.1
3.0
4
5
6.12
Here is the method to check,
a = '10'
if a.isdigit():
print "Yes it is Integer"
elif a.replace('.','',1).isdigit() and a.count('.') < 2:
print "Its Float"
else:
print "Its is Neither Integer Nor Float! Something else"
This checks if the fractional-part has any non-zero digits.
def is_int(n):
try:
float_n = float(n)
int_n = int(float_n)
except ValueError:
return False
else:
return float_n == int_n
def is_float(n):
try:
float_n = float(n)
except ValueError:
return False
else:
return True
Testing the functions:
nums = ['12', '12.3', '12.0', '123.002']
for num in nums:
if is_int(num):
print(num, 'can be safely converted to an integer.')
elif is_float(num):
print(num, 'is a float with non-zero digit(s) in the fractional-part.')
It prints:
12 can be safely converted to an integer.
12.3 is a float with non-zero digit(s) in the fractional-part.
12.0 can be safely converted to an integer.
123.002 is a float with non-zero digit(s) in the fractional-part.
Regular expressions are nice for this as they can be custom tailored in case you have some edge-cases. For example:
How do you want to handle padded numbers (numbers with leading zeros). My example here includes this consideration.
Do you need to handle exponents, e.g. 2.3E12 or 2.3e12. This is not handled here.
...in other words, if your implementation doesn't agree with an assumption mine makes, you can change it.
Regular expressions work in all versions of Python (and other languages). They can be compiled for reuse, so should be pretty quick.
# Int is:
# - Only numbers that do NOT start with 0 (protect padded number strings)
# - Exactly 0
re_int = re.compile(r"(^[1-9]+\d*$|^0$)")
# Float is:
# - Only numbers but with exactly 1 dot.
# - The dot must always be followed number numbers
re_float = re.compile(r"(^\d+\.\d+$|^\.\d+$)")
These tests all pass:
def test_re_int(self):
self.assertTrue(re_int.match("1"))
self.assertTrue(re_int.match("1543"))
self.assertTrue(re_int.match("0")) # Exactly 0 is good
self.assertFalse(re_int.match("1.54"))
self.assertFalse(re_int.match("1a4"))
self.assertFalse(re_int.match("14a"))
self.assertFalse(re_int.match("a14"))
self.assertFalse(re_int.match("00")) # Ambiguous
self.assertFalse(re_int.match("0012")) # Protect padding
def test_re_float(self):
self.assertTrue(re_float.match("1.0"))
self.assertTrue(re_float.match("1.456"))
self.assertTrue(re_float.match("567.456"))
self.assertTrue(re_float.match("0.10"))
self.assertTrue(re_float.match(".10"))
self.assertFalse(re_float.match("1.0.0")) # Too many dots
self.assertFalse(re_float.match(".10.0"))
self.assertFalse(re_float.match("..034"))
self.assertFalse(re_float.match("1"))
self.assertFalse(re_float.match("0"))
self.assertFalse(re_float.match("1a4"))
self.assertFalse(re_float.match("14a"))
self.assertFalse(re_float.match("a14"))
self.assertFalse(re_float.match("1.a4"))
self.assertFalse(re_float.match("1.4a"))
self.assertFalse(re_float.match(".a14"))
Please comment if there are any caveats, missing details or regular expression improvements I can make.
Here's my gist that not only checks for positive & negative ints, but also checks for positive & negative floats. It also checks if the string is just a normal non-number.
def int_float_or_string(string):
try:
int(string) # strict and nice
except ValueError:
if is_strictly_float(string): # float() is too permissive, this is better
return "float"
else:
return "string"
else:
return "int"
def is_strictly_float(string):
if string.startswith("-"):
string = string[1:]
return "." in string and string.replace(".", "", 1).isdecimal()
int() is great for checking an integer, but float() has a problem of being too laid back in what it calls a float.
x=input("Enter a value to check it's type: ")
def checknumber(a):
try:
a=float(a)
if int(a)/a==1:
print("This is Integer")
return a
elif a/int(a)>1:
print("This is Float")
return a
except ValueError:
print("This value is String")
return str(a)
x=checknumber(x)```
I rewrite bin Mohammed's answer as follows (number also may be negative):
from numpy import nan, isnan
def is_valid_number(s):
if (s.find('-') <= 0) and s.replace('-', '', 1).isdigit():
if (s.count('-') == 0):
s_type = 'Positive Integer'
else:
s_type = 'Negative Integer'
elif (s.find('-') <= 0) and (s.count('.') < 2) and \
(s.replace('-', '', 1).replace('.', '', 1).isdigit()):
if (s.count('-') == 0):
s_type = 'Positive Float'
else:
s_type = 'Negative Float'
else:
s_type = "Not alphanumeric!"
return('{}\t is {}'.format(s, s_type))
example:
nums = ['12', '-34', '12.3', '-12.0', '123.0-02', '12!','5-6', '3.45.67']
for num in nums:
print(is_valid_number(num))
result:
12 is Positive Integer
-34 is Negative Integer
12.3 is Positive Float
-12.0 is Negative Float
123.0-02 is Not alphanumeric!
12! is Not alphanumeric!
5-6 is Not alphanumeric!
3.45.67 is Not alphanumeric!
minimal code:
from numpy import nan, isnan
def str2num(s):
if (s.find('-') <= 0) and s.replace('-', '', 1).isdigit():
return(int(s))
elif (s.find('-') <= 0) and (s.count('.') < 2) and \
(s.replace('-', '', 1).replace('.', '', 1).isdigit()):
return(float(s))
else:
return(nan)
example:
nums = ['12', '-34', '12.3', '-12.0', '123.0-02', '12!','5-6', '3.45.67']
for num in nums:
x = str2num(num)
if not isnan(x):
print('x =', x) # .... or do something else
result:
x = 12
x = -34
x = 12.3
x = -12.0
Related
I wrote a code
i = input()
w = input()
if i % w > 0 :
print("Yes")
which takes two integers as input. If the first is exactly divisible by the second (such as 10 and 5 or 24 and 8, but not 10 and 3 or 24 and 7) it outputs “Yes”, otherwise “No”, except when the second is zero, in which case it outputs “Cannot divide by zero”. But it caused an error. Please help me know what's wrong with this code and the answer.
Cast to integer with int() and group with parentheses
i = int(input())
w = int(input())
if (i % w) > 0:
print("Yes")
Use int to change the object type from string to integer.
To handle divide by 0 use try and except.
i = int(input())
w = int(input())
try:
if (i%w) == 0:
print("Yes")
else:
print("No")
except ZeroDivisionError:
print("second input can't be 0")
Since the modulus function returns zero when the number is a divisor, you don’t even have to use and == operator.
try:
result = “Yes” if not (i % w) else “No”
except ZeroDivisionError:
result = “Divide by zero”
print(result)
I'm trying to replace a value entered by a user with a string to make the output cleaner
I thought an if statement would help, but I'm not sure how it would tie in with my intended output
def main() :
number = int(input("Enter your number: "))
base = int(input("Convert to\n" \
" Binary[2] - Octal[8] - Hexadecimal[16]: "))
if base == 2 :
"binary"
elif base == 8 :
"octal"
else:
"hexadecimal"
print("\n"+str(number) +" in "+ str(base) + " is: " + str(convert(number, 10, base)))
def convert(fromNum, fromBase, toBase) :
toNum = 0
power = 0
while fromNum > 0 :
toNum += fromBase ** power * (fromNum % toBase)
fromNum //= toBase
power += 1
return toNum
main()
What I'm trying to get:
if user enters 5 as their number and 2 as conversion. Output would be:
"5 in binary is: 101"
Try
def main() :
number = int(input("Enter your number: "))
base = int(input("Convert to\n" \
" Binary[2] - Octal[8] - Hexadecimal[16]: "))
base_string = "None"
if base == 2 :
base_string = "binary"
elif base == 8 :
base_string = "octal"
else:
base_string = "hexadecimal"
print("\n {} in {} is: {}".format(str(number), base_string, str(convert(number, 10, base))))
def convert(fromNum, fromBase, toBase) :
toNum = 0
power = 0
while fromNum > 0 :
toNum += fromBase ** power * (fromNum % toBase)
fromNum //= toBase
power += 1
return toNum
main()
Your issue was the "binary" part in the if-statement. It has virtually no effect neither on your code nor on your output. You have to store the literal representation ("binary",...) in some variable ("base_string"). Then you can use this variable in your output.
As an aside, it looks like your base conversion won't actually do what you want. You should look at How to convert an integer in any base to a string? to do the conversion properly (hexadecimal has letters A-F in it, those aren't handled by your code, for example).
To accept a name instead of a number, you need to change this line of code:
base = int(input("Convert to\n Binary[2] - Octal[8] - Hexadecimal[16]: "))
What's happening here? input() takes a line from stdin. In the interactive case, this means the user types something (hopefully a number) and then hits enter. We get that string. Then int converts that string to a number.
Your convert expects base to be a number. You want inputs like "binary" to correspond to base = 2. One way to achieve this is with a dict. It can map strings to numbers:
base_name_to_base = {'binary': 2, 'octal': 8, 'hexadecimal': 16}
base = base_name_to_base[input('Choose a base (binary, octal, hexadecimal): ')]
Note that base_name_to_base[x] can fail (raise KeyError) if x is not a key in the dict. So you want to handle this (what if the user enters "blah"?):
while True:
try:
base = base_name_to_base[input('Choose a base (binary, octal, hexadecimal): ')]
break
except KeyError:
pass
This will loop until we hit the break (which only happens when indexing into base_name_to_base doesn't raise the key error.
Additionally, you may want to handle different cases (ex. "BINARY") or arbitrary whitespace (ex. " binary "). You can do this by calling .lower() and .strip() on the string returned by input().
I want to validate a float value between 0 and 5 that can have the format x.xx
So 3.14 is valid, however 3.14a would be invalid.
if x <= 0 or x > 5 or not x.isdigit():
return 'error'
However, this will return error for 1.1, since there's the '.' character...
def is_valid(num):
try:
return 0 < float(num) <= 5
except ValueError:
print('error: not a valid floating point number')
return False
float will raise a ValueError if num is not a number which can be interpreted as float.
You can use a regex:
import re
validate = lambda x: re.match(r"^[0-4]\.[0-9]{2}|5\.00$", x) is not None
x = "1.21"
if not validate(x):
print('error')
This will match a string containing a number with the y.xx format, where y is in the 0-4 range and y can be any. This covers the 0.00-4.99 range. Finally, we cover 5.00 as a special case.
If you need to accept 4.0 as well, you can slightly modify the regex as
r"^[0-4]\.[0-9]{1,2}|5\.00?$"
so that the second digit becomes optional.
def is_string_a_float_between_0_and_5(s):
try:
return 0 <= float(s) <= 5
except ValueError:
return False
x = "3.14a"
try:
if float(x) <= 0 or float(x) > 5:
print('error')
except:
print('error')
I think isinstance will solve your problem
Convert your string to a float. If it fails that test then you know you don't have a number. If it converts, then you can check if it is between 0 and 5:
x = '3.14'
try:
x = float(x)
except ValueError:
return 'error'
if x <= 0 or x > 5:
return 'error'
If x is '3.14a' then it will hit the ValueError and return 'error'
You're missing a bit of information here. Are you expecting that x is a string? If that's the case, you need to cast x to a float before testing if it's between 0 and 5.
Secondly, it's considered "non-pythonic" to check your variable types. Python is a "duck typed" language, and you're not supposed to check types unless absolutely necessary. Here's a great answer about if someone misuses your function.
To answer the real question about checking if a number is between 0 and 5:
y = float(x) # Will throw exception if x is not castable to a float
if y < 0 or y > 5:
raise ValueError("Bad x parameter!")
I am a complete beginner to Python. I wrote some code to perform base conversion and I was wondering if there were better alternatives that were shorter to code (one-liners) or significantly faster. The code looks ugly and feels "non-Pythonic" though being a beginner I should not have any such opinion. Any feedback to improve the code would be appreciated. This is purely for learning purposes.
#!/usr/bin/env python
import math
def number_to_digits( number, radix ):
'Converts a number into a vector of digits in given radix'
digits = [0]*int(math.ceil(math.log(number,radix)))
for ii in range(len(digits)):
(number,digit) = divmod(number,radix)
digits[ii] = digit
return digits
def digits_to_number( digits, radix ):
'Converts a vector of non-negative digits in given radix into a number'
number = 0;
for ii in range(len(digits)-1,-1,-1):
number *= radix
number += digits[ii]
return number
if __name__ == '__main__':
try:
number = int(raw_input('Enter number: '))
if number <= 0: raise ValueError()
radix = int(raw_input('Enter radix: '))
if radix <= 0: raise ValueError()
digits = number_to_digits(number,radix)
print digits
number_again = digits_to_number(digits,radix)
if not number_again == number:
print 'test failed'
except ValueError:
print 'unexpected input'
A sample session on the terminal produces:
Enter number: 44
Enter radix: 6
[2, 1, 1]
It is easy to check that 2 + 1*6 + 1*6**2 == 44. Thanks!
Here's a nice recursive version that will convert up to hexadecimal from Problem Solving with Algorithms and Data Structures
def toStr(n,base):
convertString = "0123456789ABCDEF"
if n < base:
return convertString[n]
else:
return toStr(n//base,base) + convertString[n%base]
print(toStr(1453,16))
Python provides some built-in functions to convert a value represented in one Integer base to another Integer base. Integer is represented in four forms i.e. decimal, binary, octal, and hexadecimal form.
Python provides built-in bin() functions to convert from non-binary number to binary number, oct() function to convert from non-octal number to octal number and hex() function to convert from non-hexadecimal number to hexadecimal number. These functions return a string literal to represent the values.
You can learn these functions from the tutorial on Integer base Conversion Functions in Python
You can find (slightly) cleaner example in the following thread:
Python elegant inverse function of int(string,base).
Taking the top ranked example, you can clean it up a bit to:
def digit_to_char(digit):
if digit < 10:
return str(digit)
return chr(ord('a') + digit - 10)
def str_base(number, base):
while number > 0:
number, digit = divmod(number, base)
yield digit_to_char(digit)
Results in:
>>> list(str_base(44, 6))
['2', '1', '1']
If you don't care about bases larger than 10, it simplifies to:
def str_base(number, base):
if base > 10:
raise ValueError('Base must be less than 10')
while number > 0:
number, digit = divmod(number, base)
yield digit
>>> list(str_base(44, 6))
[2, 1, 1]
when I try this
if question.isdigit() is True:
I can type in numbers fine, and this would filter out alpha/alphanumeric strings
when I try 's1' and 's' for example, it would go to (else).
Problem is, when I put negative number such as -1, '.isdigit' counts '-' sign as string value and it rejects it. How can I make it so that '.isdigit' allows negative symbol '-'?
Here is the code. Of the thing i tried.
while a <=10 + Z:
question = input("What is " + str(n1) + str(op) + str(n2) + "?")
a = a+1
if question.lstrip("-").isdigit() is True:
ans = ops[op](n1, n2)
n1 = random.randint(1,9)
n2 = random.randint(1,9)
op = random.choice(list(ops))
if int(question) is ans:
count = count + 1
Z = Z + 0
print ("Well done")
else:
count = count + 0
Z = Z + 0
print ("WRONG")
else:
count = count + 0
Z = Z + 1
print ("Please type in the number")
Use lstrip:
question.lstrip("-").isdigit()
Example:
>>>'-6'.lstrip('-')
'6'
>>>'-6'.lstrip('-').isdigit()
True
You can lstrip('+-') if you want to consider +6 a valid digit.
But I wouldn't use isdigit, you can try int(question), it'll throw an exception if the value cannot be represented as int:
try:
int(question)
except ValueError:
# not int
Use a try/except, if we cannot cast to an int it will set is_dig to False:
try:
int(question)
is_dig = True
except ValueError:
is_dig = False
if is_dig:
......
Or make a function:
def is_digit(n):
try:
int(n)
return True
except ValueError:
return False
if is_digit(question):
....
Looking at your edit cast to int at the start,checking if the input is a digit and then casting is pointless, do it in one step:
while a < 10:
try:
question = int(input("What is {} {} {} ?".format(n1,op,n2)))
except ValueError:
print("Invalid input")
continue # if we are here we ask user for input again
ans = ops[op](n1, n2)
n1 = random.randint(1,9)
n2 = random.randint(1,9)
op = random.choice(list(ops))
if question == ans:
print ("Well done")
else:
print("Wrong answer")
a += 1
Not sure what Z is doing at all but Z = Z + 0 is the same as not doing anything to Z at all 1 + 0 == 1
Using a function to take the input we can just use range:
def is_digit(n1,op,n2):
while True:
try:
n = int(input("What is {} {} {} ?".format(n1,op,n2)))
return n
except ValueError:
print("Invalid input")
for _ in range(a):
question = is_digit(n1,op,n2) # will only return a value when we get legal input
ans = ops[op](n1, n2)
n1 = random.randint(1,9)
n2 = random.randint(1,9)
op = random.choice(list(ops))
if question == ans:
print ("Well done")
else:
print("Wrong answer")
If you do not wish to go for try... except, you could use regular expression
if re.match("[+-]?\d", question) is not None:
question = int(question)
else:
print "Not a valid number"
With try... except, it is simpler:
try:
question = int(question)
except ValueError:
print "Not a valid number"
If isdigit is must and you need to preserve the original value as well, you can either use lstrip as mentioned in an answer given. Another solution will be:
if question[0]=="-":
if question[1:].isdigit():
print "Number"
else:
if question.isdigit():
print "Number"
I have just had a similar question on edabit where I realised that negative numbers returned as False whilst using isnumeric(). I have put my solution below:
Create a function that takes a list of strings and integers, and filters out the list so that it returns a list of integers only.
def filter_list(list):
numbers = [i for i in list if str(i).isnumeric() == True]
for i in list:
try:
int(i)
if i <0:
numbers.append(i)
except ValueError:
continue
return numbers
list = [1,2,3,'a','b','c', -6, 0]
print(filter_list(list))
I am still new to Python so this is a basic attempt. Feel free to let me know if there is a much easier or better looking way.
To check if your input string is numeric or not, even in cases when you enter negative values or floats you can do this:
if string.replace('.','').replace('-','').isnumeric():
print(string + ' is a number')
If you want to check specifically if your string is a negative number you can do this:
if string[0] == '-' and string[1:].replace('.','').isnumeric():
print(string + ' is a negative number')
I know it's late, but I just stumbled appon this question and I had a similar problem wich I solved this way:
#staticmethod
def getStringToFloatOrNone(value):
if value == None:
return None
if not str(value).replace(",","").replace(".","").replace("-","").strip().isdigit():
return 0
return value if isinstance(value, float) or isinstance(value, int) else float(Helper.createViableFloatOrIntString(value))
return int(float(value)) if isinstance(value, float) or isinstance(value, int) else int(float(Helper.createViableFloatOrIntString(value)))
Just replace all the common delimitter and try if it's a digit.
If yes, get the actual value as float.
Simple way to do this using lambda,
is_numeric = lambda x: x.replace('.', '', 1).replace('-', '', 1).isdigit()
You can use this like:
if is_numeric(question):
## your code here ##
#Hurri have done something similar, but afraid it return True for values like IP addresses.