Reputation: 71
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.
Upvotes: 0
Views: 544
Reputation: 51997
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.
Upvotes: 0
Reputation: 659
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()
Upvotes: 1
Reputation: 6190
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))
Upvotes: 0