0

Right now when I run this, I get an error saying "4 is not in list" for line if (numberList.index(digit)-1) % 2 == 0: Not sure where I went wrong but any tips would be appreciated. It starts at the second to last letter, and the if statement checks if its every other by .index(digit) % 2 == 0

def credit():
      cardType = ""
      mastercard = ["51", "52", "53", "54", "55"]
      american_express = ["34", "37"]
      total = 0
      while True:
            number = input("Enter Valid Credit Card Number: ")
            if " " in str(number):
                  print("INVALID")
                  continue
            number = int(number)
            if len(str(number)) == 15 and str(number)[0:2] in american_express:
                  cardType = "American Express"
                  break
            elif len(str(number)) == 16:
                  if str(number)[0] == "4":
                        cardType = "Visa"
                  elif str(number)[0:2] in mastercard:
                        cardType = "Mastercard"
                  break
            elif len(str(number)) == 13:
                  cardType = "Visa"
                  break
            else:
                  print("INVALID CARD")
                  continue

      numberList = []
      for n in str(number):
            numberList.append(n)

      for digit in numberList[::-2]:
            digit = int(digit)
            if numberList.index(digit) % 2 == 0:
                  if (digit*2) >= 10:
                        total += ((digit*2) / 10)
                        total += ((digit*2) % 10)
                  elif (digit*2) < 10:
                        total += digit
            else:
                  if digit > 10:
                        total += (digit / 10)
                        total += (digit % 10)
                  elif digit < 9:
                        total += digit
      if (total % 10) == 0:
            print(cardType)
      else:
            print("INVALID CARD")
      print(total)
      
credit()
            

3 Answers 3

1

Your for digit in numberList[::-2]: only processes every other digit, completely skipping the digits in between. Then, assuming you're going through all digits, you find the position of a digit within the string which will not give the right value if there are duplicate digits in the code. In addition to that, even if there were no duplicate digits in the code, .index() finds the position from the beginning so the odd/even test you make will give the wrong answer if the code has an even number of positions.

To properly perform the Luhn test, you have to invert the code before you start. Then everything becomes simpler and can be performed sequentially (e.g. using sums and comprehensions).

For example:

def luhnTest(code):
    digits = [*map(int,code[::-1])]
    cd = sum(digits) + sum(d - (d>4)*9 for d in digits[1::2])
    return not cd % 10   

Every digit (including the check digit) is added up once to validate the check digit. Digits at odd positions (in the reversed code) are added again (i.e. doubled) but, if the doubling is > 10, the digits of the doubled value are added together, which is equivalent to subtracting 9 (i.e. - (d>4)*9).

# test set from https://en.wikipedia.org/wiki/Luhn_algorithm
tests = [79927398710, 79927398711, 79927398712, 79927398713, 79927398714,
         79927398715, 79927398716, 79927398717, 79927398718, 7992739871]

for t in tests: print(t,luhnTest(str(t)) 

79927398710 False
79927398711 False
79927398712 False
79927398713 True
79927398714 False
79927398715 False
79927398716 False
79927398717 False
79927398718 False
7992739871 False

With a bit of fiddling, you can factorize this into a single comprehension:

return 1>sum(d+(i%2)*(d-(d>4)*9) for i,d in enumerate(map(int,code[::-1])))%10
Sign up to request clarification or add additional context in comments.

Comments

0

This happens because you have converted that character to an int:

      for digit in numberList[::-2]:
            digit = int(digit)
            if numberList.index(digit) % 2 == 0:

numberList is a list of individual characters. But a character is not the same as an integer: "9" != 9, so index will not find the integer.

So either do numberList.index(str(digit)) or delay the statement digit = int(digit) until after you have performed the if condition. Then you will need to put that statement in both the if and the else block.

You can completely avoid this situation by making numberList a list of integers (instead of characters):

Replace this:

      numberList = []
      for n in str(number):
            numberList.append(n)

with:

      numberList = list(map(int, s))

And now you don't need the statement digit = int(digit).

Comments

0

@trincot pointed out one indexing error. The other is the numberList.index(str(digit)) will return the index of the first digit that matches, so if their are two fours, for example, it will give the same index for both.

Here's a working algorithm:

def card_type(number):
    cardType = ""
    mastercard = '51','52','53','54','55'
    american_express = '34','37'
    digits = len(number)
    if digits == 15 and number[:2] in american_express:
        return 'American Express'
    elif digits == 16 and number[0] == '4' or digits == 13:
        return 'Visa'
    elif number[:2] in mastercard:
        return 'Mastercard'
    else:
        return 'Unknown'

def credit(number):
      # https://en.wikipedia.org/wiki/Luhn_algorithm
      total = 0
      for digit in number[-2::-2]: # every other digit from right starting 2nd-to-last
          value = int(digit) * 2
          total += value if value < 10 else value - 9 # value-9 same as sum of two digits, e.g. 16 => 1+6 = 16-9 = 7
      for digit in number[-1::-2]: # every other digit from right starting from last
          total += int(digit)
      if total % 10 == 0:
          return card_type(number)
      return 'Invalid'

print(credit('4123456789123450')) # Visa
print(credit('341234567891232'))  # AmEx
print(credit('5112345678912349')) # Mastercard
print(credit('1234567891233'))    # Visa
print(credit('123'))              # bad check
print(credit('125'))              # valid but unrecognized
Visa
American Express
Mastercard
Visa
Invalid
Unknown

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.