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
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
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
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'
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
for a free online Python tutorial I need to:
to write a function which checks if a given credit card number is
valid. The functioncheck(S)
should take a stringS
as input. First,
if the string does not follow the format"#### #### #### ####"
where
each#
is a digit, then it should returnFalse
. Then, if the sum of
the digits is divisible by10
(a “checksum” method), then the
procedure should returnTrue
, else it should returnFalse
. For
example, ifS
is the string"9384 3495 3297 0123"
then although the
format is correct, the digit sum is72
so you should returnFalse
.
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
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
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
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'
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