Credit card check exercise python

Question:

for a free online Python tutorial I need to:

to write a function which checks if a given credit card number is
valid. The function check(S) should take a string S as input. First,
if the string does not follow the format "#### #### #### ####" where
each # is a digit, then it should return False. Then, if the sum of
the digits is divisible by 10 (a “checksum” method), then the
procedure should return True, else it should return False. For
example, if S is the string "9384 3495 3297 0123" then although the
format is correct, the digit sum is 72 so you should return False.

The following shows what I have come up with. I think my logic is correct but don’t quite understand why it is giving me the wrong value. Is there a structural issue in my code, or am I using a method incorrectly?

def check(S): 
    if len(S) != 19 and S[4] != '' and S[9] != '' and S[14] != '':
        return False                # checking if the format is correct

    S = S.replace(" ",'')         # Taking away spaces in the string
    if not S.isdigit():
        return False             # checking that the string has only numbers

    L = []            
    for i in S:
        i = int(i)                # Making a list out of the string and converting each character to an integer so that it the list can be summed 
        L.append(i)
    if sum(L)//10 != 0:        # checking to see if the sum of the list is divisible by 10
        return False
Asked By: iaianmcd

||

Answers:

You are not testing for spaces, only for empty strings, which you’ll never find when using straight indices on a python string.

Moreover, you should return False if any of those 4 conditions is true, not if they are all true at the same time:

if len(S) != 19 or S[4] != ' ' or S[9] != ' ' or S[14] != ' ':
    return False

Next, you replace the spaces, but don’t check the length again. What if I had given you 19 spaces:

S = S.replace(" ", '')
if len(S) != 16 or not S.isdigit():
    return False

Last, you want first collect all the digits, and check if there is a remainder:

L = map(int, S)  # makes S into a sequence of integers in one step
if sum(L) % 10 != 0:  # % calculates the remainder, which should be 0
    return False

and don’t forget to return True if all those tests have passed:

return True

at the end.

Put that all together and you get:

>>> def check(S):
...     if len(S) != 19 or S[4] != ' ' or S[9] != ' ' or S[14] != ' ':
...         return False
...     S = S.replace(" ", '')
...     if len(S) != 16 or not S.isdigit():
...         return False
...     L = map(int, S)  # makes S into a sequence of integers in one step
...     if sum(L) % 10 != 0:  # % calculates the remainder, which should be 0
...         return False
...     return True
... 
>>> check('9384 3495 3297 0123')
False
>>> check('9384 3495 3297 0121')
True
Answered By: Martijn Pieters

Here is a method based on a regex:

import re
def cc(pat):
    # check for the pattern #### #### #### #### with each '#' being a digit
    m=re.match(r'(d{4})s(d{4})s(d{4})s(d{4})$', pat.strip())
    if not m:
        return False
    # join all the digits in the 4 groups matched, 
    # turn into a list of ints, 
    # sum and 
    # return True/False if divisible by 10: 
    return sum(int(c) for c in ''.join(m.groups()))%10==0

>>> cc('9384 3495 3297 0123')
False
>>> cc('9384 3495 3297 0121')
True
Answered By: dawg

Here is my approach, it is a bit longer code but I like using defining functions. For some reason code does not work on Computer Science Circles website, but it works in PyCharm program.

    def CardNumber():
        global card     #  Making variable global for function SumCardNumDigits(); see below
        card = input()  # Credit card number is entered
        return card


    def check(S):
        CardNumber = S
        SplitCardNum = CardNumber.split()      # Split credit card number into a list, so we get [####, ####, ####, ####]
        for i in range(0, len(SplitCardNum)):  # Checking if each item in list has length of four strings and each item is
                                               # an actual a number

            if len(SplitCardNum[i]) == 4 and SplitCardNum[i].isdigit():
            SplitCardNum.insert(i, True)   # We add to a list a True value at position i
                del SplitCardNum[i + 1]    # We delete items at position i + 1
            return SplitCardNum


    def checkFormat(SplitCardNum):
        if SplitCardNum == [True] * 4:  # Checking if all above conditions are met in function check(S)
                                        # So the returned value from previous function is a list [True, True, True, True]
            return True
        else:
            return False

    def SumCardNumDigits():
        Ncard = card                    # Using global variable 'card' from function CardNumber()
        SumN = 0
        for i in Ncard:            # Summing up all digits in string 'Ncard', if i position in a string is empty space " "
                                   # we skip a step.
            if i == " ":
                continue
            else:
                SumN += int(i)
            return SumN


    def DivideByTen(SplitCardNum):
        if SplitCardNum == True:        # If conditions from function check(S) are met, we divide the sum of digits
                                        # of credit card number by 10
            SumNumber = SumCardNumDigits() % 10  # We do this by using the returned value of function SumCardNumDigits()
            global SumNumber       # <--- Fixed code
            return SumNumber
        else:
            return False


    def IsDivideByTen(SumNumber):
        check = checkFormat(SplitCardNum)      # Finally we check if the sum of digits of credit card number is divisible by 10
        if SumNumber == 0 and check == True:   # <--- Fixed code
            return True
        else:
            return False


    print(IsDivideByTen(DivideByTen(checkFormat(check(CardNumber())))))  # Output final result

    # You can test this code at: http://cscircles.cemc.uwaterloo.ca/visualize/#mode=edit  and see how it works.
    # Try for '9384 3495 3297 4523' and '9384 3495 3297 4526'
Answered By: Pifko6

here is my approach, learning Python at the moment and haven’t seen this answered this way:

def check(S):
   if len(S) != 19 or len(S[4:19:5].strip()) != 0:
      return False
   digits = S.replace(" ", '')
   if not digits.isdigit():
      return False
   sum = 0
   for digit in digits: 
      sum += int(digit)
   if sum % 10 == 0:
      return True
   else:
      return False
Answered By: jenn
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.