ISBN Checker - validating user input - python

So, my task is to validate the user's input for each of the ISBN 10 digits that they input. I need to make sure that 1) the user input isn't blank, 2) the user input is only an integer (which I've done), and 3) that they only enter ONE digit.
Sorry, I have seen a few similar questions on this, but I wanted to keep the try-except statement (if possible) so the similar questions weren't too helpful.
How can I go about validating against blank inputs and that only one digit is entered?
Here is the code:
print("You will be asked to enter an ISBN-10 Number. Please enter it digit by digit.")
ISBN10NumberList = []
ISBN10NumberAdder = 0
for count in range (10):
validInput1 = True
if (count <= 8):
while validInput1 != False:
try:
ISBN10NumberList.append(int(input("Please enter the ISBN digit: ")))
validInput1 = False
except ValueError:
print("That is not a valid input! Please enter a integer only.")
elif (count == 9):
CheckDigit10 = input("Please enter the ISBN digit: ")
print("")
if CheckDigit10 == "X" or CheckDigit10 == "x":
CheckDigit10 = 10
for count in range (0, 9):
ISBN10NumberAdder += int(ISBN10NumberList[count]) * (10 - count)
CheckDigit10 = int(CheckDigit10)
CheckingCheckDigit = 11-(ISBN10NumberAdder % 11)
if (CheckDigit10 == CheckingCheckDigit):
print("This is a valid ISBN!")
else:
print("This is not a valid ISBN!")

So yes - you are making life hard for yourself and your user - here is a simpler implementation where the user can enter the ISBN in one fell swoop. I factored out some things into functions to make things a little cleaner
In the main loop, the user will be repeatedly prompted for an ISBN until they enter a valid one
def verify_check(isbn_str):
last = isbn_str[-1] # Last character
if last == 'X':
check = 10
else:
check = int(last)
# This part was fine in your original:
adder = 0
for count in range(9):
adder += int(isbn_str[count]) * (10 - count)
if adder % 11 != check:
raise ValueError("Checksum failed")
def verify_isbn10(isbn_str):
if len(isbn_str) != 10:
raise ValueError("ISBN must be 10 digits long")
# Check that the first nine chars are digits
for char in isbn_str[:-1]:
if not char.isdigit():
raise ValueError("ISBN must contain digits or X")
# Special case for the last char
if not (isbn_str[-1].isdigit or isbn_str[-1] == "X"):
raise ValueError("ISBN must contain digits or X")
verify_check(isbn_str)
# Main code:
while 1:
try:
isbn_str = raw_input("Enter ISBN: ")
verify_isbn(isbn_str)
break
except ValueError as e:
print "Whoops:", e
# At this point, isbn_str contains a valid ISBN
If you want to use Kevin's suggestion and try your hand at regexes, you can use something like the following replacement for verify_isbn10. Note that it doesn't explain to the user exactly what was wrong.
import re
isbn_re = re.compile(r"""
^ #Start of string
[0-9]{9} # Match exactly 9 digits
[0-9X] # Match a digit or X for the check digit
$ # Match end of string
""", re.VERBOSE)
def verify_isbn10(isbn_str):
m = isbn_re.match(isbn_str)
if m is None: #User didn't enter a valid ISBN
raise ValueError("Not a valid ISBN")
verify_check(isbn_str)

Related

How to using if for just a number, when the minus sign (-) just one in the front of the number that input from a user

So, I am tried to make a program that users just can input a number, but for the minus number, the minus sign (-) just one in front of the number. When the users input the wrong input, it will retry just until 5 times.
So, I just want the user input number like this
-1
-12
-123
Not like this
--1
--12
1-
1--
12-
12--
-1-
-12-
1-1
-1-1
and some tricks like that
The explanation for if statements:
len(nama) > 0
This is to avoid if the user inputs a blank input or just press Enter.
re.match("^[-0-9]*$", nama)
This is to make the users just input a number (0-9) and a minus sign (-).
nama[1:] != "-"
This is to make the user just can input the minus sign (-) in front of the number.
nama[1:-1] != "-"
This is to avoid the user input minus sign (-) after the first minus sign until the lattes.
all([len(nama) > 0, re.match("^[-0-9]*$", nama), nama[1:] != "-", nama[1:-1] != "-"])
This for if all statements right it will go to next. But I didn't sure using AND or OR for this or the code not look so good.
I tried that, but why after I input more than one minus sign (-) in front of the number and in the back, still print "Benar". That not what I want.
This is my first simple code:
for retry_nama in range(5):
nama = input("masukkan nama: ")
if all([len(nama) > 0, re.match("^[-0-9]*$", nama), nama[1:] != "-", nama[1:-1] != "-"]):
print("Benar")
input("press ENTER to exit")
break
print("salah, try again.")
else:
print("You keep making invalid name, exiting now.")
sys.exit(1)```
There is not need for regular expressions for such a simple check:
def is_int(s):
s = str(s)
if s[0] in ('-', '+'):
return s[1:].isdigit()
return s.isdigit()
for retry_nama in range(5):
nama = input("masukkan nama: ")
if is_int(nama):
print("Benar")
input("press ENTER to exit")
break
print("salah, try again.")
else:
print("You keep making invalid name, exiting now.")
A different approach would be to cast the number to int and see what happens:
sample_input = [
"-1",
"-12",
"-123",
"--1",
"--12",
"1-",
"1--",
"12-",
"12--",
"-1-",
"-12-",
"1-1",
"-1-1",
]
for inp in sample_input:
try:
number = int(inp)
print(f"Input is a valid int: {number}")
except ValueError:
print(f"{inp} is not a valid int.")
Which prints:
Input is a valid int: -1
Input is a valid int: -12
Input is a valid int: -123
--1 is not a valid int.
--12 is not a valid int.
1- is not a valid int.
1-- is not a valid int.
12- is not a valid int.
12-- is not a valid int.
-1- is not a valid int.
-12- is not a valid int.
1-1 is not a valid int.
-1-1 is not a valid int.
Which solves your examples.
Cheers!

Checking user input to see if it satisfies two conditions

As part of a larger menu-driven program, I'd like to test user input to see if that input:
is an integer AND
if it is an integer, if it is within the range 1 to 12, inclusive.
number = 0
while True:
try:
number = int(input("Enter a whole number between 1 and 12 >>> "))
except ValueError:
print("Invlaid input, please try again >>> ")
continue
else:
if not (1<= number <=12):
print("Need a whole number in range 1-12 >>> ")
continue
else:
print("You selected:",number)
break
I'm using Python 3.4.3, and wanted to know if there's a more succinct (fewer lines, better performance, more "Pythonic", e.g.) way to achieve this? Thanks in advance.
You don't need anything bar one if in the try:
while True:
try:
number = int(input("Enter a whole number between 1 and 12 >>> "))
if 1 <= number <= 12:
print("You selected:", number)
break
print("Need a whole number in range 1-12 >>> ")
except ValueError:
print("Invlaid input, please try again >>> ")
Bad input will mean you go straight to the except, if the input is good and is in your accepted range, the print("You selected:", number) and will be executed then we break or else print("Need a whole number in range 1-12 >>> ") will be executed if is outside the range.
Your code looks pretty good to me. Minor fix-ups (spelling, indentation, unnecessary continues):
while True:
try:
number = int(input("Enter a whole number between 1 and 12 >>> "))
except ValueError:
print("Invalid input, please try again >>> ")
else:
if 1 <= number <= 12:
print("You selected: {}".format(number))
break
else:
print("Need a whole number in range 1-12 >>> ")
Use isdigit() to check for non-digit characters. Then you shouldn't need to catch the exception. There's only one if and it uses operator short-circuiting to avoid doing int(blah) if blah contains non-digits.
while True:
num_str = raw_input("Enter a whole number between 1 and 12 >>> ")
if num_str.isdigit() and int(num_str) in range(1,13):
print("You selected:",int(num_str))
break
else:
print("Need a whole number in range 1-12 >>> ")
I don't think you need a whole try/except block. Everything can be fit into a single condition:
number = raw_input("Enter a whole number between 1 and 12 >>> ")
while not (number.isdigit() and type(eval(number)) == int and 1<= eval(number) <=12):
number = raw_input("Enter a whole number between 1 and 12 >>> ")
print("You selected:",number)

Check to see if capital letters exist in string [duplicate]

This question already has answers here:
How to test if a string has capital letters
(3 answers)
Closed 2 years ago.
I was supposed to write a program that verifies a username. The username must consist of at least 8-15 letters, no alphanumeric values. So, you can only have numbers and letters. You can't have numbers at the beginning or the end. And, You MUST have at least one capital and lower case letter and at least one number. I got how to do everything but how to get the program to check to see if it contains any capital letters. I tried to do the " if not in " but no luck. This is what I have so far.
username = input("please enter a name: ")
for i in username:
while len(username) < 8 or len(username) > 15:
print("Password is too long or too short")
username = input("please enter a name: ")
j = 31
while j < 47:
j += 1
while chr(j) in i:
print("No alphanumeric values allowed.")
username = input("please enter a name: ")
k = 57
while k < 64:
k += 1
while chr(k) in i:
print("No alphanumeric values allowed.")
username = input("please enter a name: ")
l = 47
while l < 57:
l += 1
while chr(l) in username[0]:
print("you cannot have a number in the beggining")
username = input("please enter a name: ")
while chr(l) in username[-1]:
print("you cannot have a number in the end")
username = input("please enter a name: ")
You can use any with a generator to test if the string has a capital letter
testString = "abjKcf"
print(any(x.isupper() for x in testString)) #true
Good Solution
As for addressing a solution to your problem, welcome to the world of generator expressions and assertions
while True:
testString = input()
try:
assert 8 <= len(testString) <= 15, "String must be between 8 and 15 characters"
assert all(x.isalnum() for x in testString), "String must be alphanumeric"
assert any(x.isupper() for x in testString), "String must contain one capital"
assert any(x.islower() for x in testString), "String must contain one lowercase"
assert any(x.isdigit() for x in testString), "String must contain one digit"
assert testString[0].isdigit() == False, "No numbers at start"
assert testString[-1].isdigit() == False, "No numbers at end"
break #if we haven't hit any errors then the username fits the criterion
except Exception as e:
print(e)
Really ugly solution (as requested)
Basically you set up some booleans and try to disprove them by looping through every character and checking if it meets some conditions
while True:
testString = input()
allAlphaNumeric = True
oneCapital = False
oneLowerCase = False
oneDigit = False
for letter in testString:
if not letter.isalnum():
oneAlphaNumeric = False
if letter.isupper():
oneCapital = True
if letter.islower():
oneLowerCase = True
if letter.isdigit():
oneDigit = True
numberAtStart = testString[0].isdigit()
numberAtEnd = testString[-1].isdigit()
if allAlphaNumeric and oneCapital and oneLowerCase and oneDigit and not numberAtEnd and not numberAtStart:
break
if not 8 <= len(testString) <= 15:
print("String must be between 8 and 15 characters")
if not allAlphaNumeric:
print("Your string must be alphanumeric!")
if not oneCapital:
print("Your string must contain at least one capital letter")
if not oneLowerCase:
print("Your string must contain atleast one lowercase letter")
if not oneDigit:
print("Your string must contain atleast one digit")
if numberAtStart:
print("You cannot have a number at the start")
if numberAtEnd:
print("You cannot have a number at the end")

Why am I getting this Error "IndexError: string index out of range"

We've been asked to code a program which validate GTIN-8 codes.
The valdation is as follows:
Multiply the first 7 digits alternately by 3 then 1
Add them up
Subtract that number from the equal or higher multiple of 10
The resulting number is the eighth digit
Here's my code:
def validgtin():
gtin = input("Enter the 8 digits of GTIN-8 product code: ")
valid = False
while valid == False:
if gtin.isdigit():
gtin = str(gtin)
if len(gtin) == 8:
valid = True
else:
print("That is not correct, enter 8 digits, try again: ")
gtin = input("Enter the 8 digits of GTIN-8 product code: ")
else:
print("That is not correct, type in numbers, try again: ")
gtin = input("Enter the 8 digits of GTIN-8 product code: ")
sumdigit = 3*(int(gtin[0])) + 1*(int(gtin[1])) + 3*(int(gtin[2])) + 1*(int(gtin[3])) + 3*(int(gtin[4])) + 1*(int(gtin[5])) + 3*(int(gtin[6])) #sum of the digits
gtin = str(gtin)
valid1 = False
while not valid1:
if sumdigit%10 == 0:
eightdigit = 0
else:
eightdigit = (((sumdigit + 10)//10)*10) - sumdigit
if eightdigit == (gtin[7]):
valid1 = True
print("Your GTIN-8 product code is valid.")
else:
print("Your GTIN-8 product code is not valid.")
gtin = input("Enter the 8 digits of GTIN-8 product code: ")
return
validgtin()
When I run this code and type an invalid GTIN-8 code it says that the code is invalid and prompts me to type in a new GTIN-8 code
BUT
After I type in a new and valid GTIN-8 code it still says it is invalid
AND
After that this happens:
Traceback (most recent call last):
File "C:\Users\Yash Dwivedi\Documents\Year 10\GCSE Computing\Assignment\Task 1 v2.py", line 29, in validgtin
if eightdigit == (gtin[7]):
IndexError: string index out of range
I don't understand why
I'll be thankful for any help.
I would suggest to make a "is_valid_gtin" function that just checks if a GTIN is valid, without I/O. Then a simple "main()" to check the code:
def is_valid_gtin(gtin):
if len(gtin) != 8 or not gtin.isdigit():
return False
sum = 0
for i in list(gtin)[0:6:2]:
sum += 3*int(i)
for i in list(gtin)[1:6:2]:
sum += int(i)
checksum = (10 - sum % 10) % 10
return checksum == int(gtin[7])
def main():
while (True):
gtin = input("Enter the 8 digits of GTIN-8 product code: ")
if is_valid_gtin(gtin):
print("Your GTIN-8 product code is valid.")
break
else:
print("That is not correct, try again.")
if __name__ == '__main__':
main()
Here's my quick implementation. Sadly I don't have any test data to check it's correct!
def _round_up_ten(number):
if number % 10 == 0:
return number
return 10 * (1 + (number / 10))
def validate_gtin(gtin):
if not gtin.isdigit() or len(gtin) != 8:
raise ValueError("GTIN must be an 8-digit number")
digits = [int(digit) for digit in gtin[:-1]]
check_digit = int(gtin[-1])
multiplied_digits = (
digits[0] * 3
+ digits[1]
+ digits[2] * 3
+ digits[3]
+ digits[4] * 3
+ digits[5]
+ digits[6] * 3
)
expected_check_digit = _round_up_ten(multiplied_digits) - multiplied_digits
if check_digit!= expected_check_digit:
raise ValueError("Incorrect check digit ({}) (expected {})".format(check_digit, expected_check_digit))
The bug is in the line
if eightdigit == (gtin[7]):
eightdigit is an int but gtin[7] is a string. This comparison is thus always false -- hence you are in an infinite loop (as long as you enter strings with at least 8 characters). You grow frustrated and then just hit the enter key -- which passes your code the empty string, which, lacking an eighth character, triggers the index out of range error.
Thus you would need:
if eightdigit == int(gtin[7]):
to fix that particular bug, though this would still leave you with a logical error -- since the loop at the bottom of your code doesn't validate the input and you are trying to check new candidate gtins against a checkdigit computed with a previous input. You should probably follow #JacquesSupik 's excellent idea and refactor the code so that the logic of validation is separated from the I/O logic.

Asking for 10-digit numbers

I am testing that the user input is of length 10 and only contains numbers. At the moment, my code is:
while True:
number = input("Enter number: ")
try:
if len(number) != 10:
print ("Enter 10 digits\n")
continue
except ValueError:
print ("Enter only numbers\n")
continue
else:
break
The program will ask for user input, then test that it is of 10 length and only contains integers.
Currently, user input is read as a string so that if it began with a '0', then this would be included in len(), if you know what I mean? For example, if I inputted '0123456789', this would be seen to have a length of 10 and not 9 because it begins with '0'.
Also, I wanted to ensure that if the user entered 10 letters, this would be declined because only numbers are allowed.
Any help would be greatly appreciated.
Thank you.
At no point in your code do you actually check that the input is an integer..
You could do something like this:
while True:
number = input("Enter number: ")
if not number.isdigit(): # check if a string contains a number with .isdigit()
print ("Enter only numbers\n")
continue
elif len(number) != 10:
print ("Enter 10 digits\n")
continue
else:
break
Info on str.isdigit():
Type: method_descriptor
String Form:<method 'isdigit' of 'str' objects>
Namespace: Python builtin
Docstring:
S.isdigit() -> bool
Return True if all characters in S are digits
and there is at least one character in S, False otherwise.
while True:
number = input("Enter number: ")
try:
number = int(number)
except ValueError:
print ("Enter only numbers")
else:
if 10 > number//10**9 > 0 :
print ("Enter 10 digits")
continue
else:
break
You can checking for an error while casting to a number (integer)
try:
if len(number) != 10 and int(number):
print ("Your number is good!")
break
else :
print("Your number isn't good!")
continue
except ValueError:
print('only digit please')
continue
Note that the flaw in len(number) is that the nine firsts digit could be 0.
To ensure that is a valid number beetwen 1000000000 and 999999999 you can do the following:
import math
while True:
try:
if math.floor(math.log10(int(number)))+1 == 10:
print ("Your number is good!")
break
else :
print("Your number isn't good!")
continue
except ValueError:
print('only digit please')
continue

Categories