Yash Dwivedi
Yash Dwivedi

Reputation: 71

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:

  1. Multiply the first 7 digits alternately by 3 then 1

  2. Add them up

  3. Subtract that number from the equal or higher multiple of 10

  4. 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

Answers (3)

John Coleman
John Coleman

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

Jacques Supcik
Jacques Supcik

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

Tom Dalton
Tom Dalton

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

Related Questions