Python Credit Card Check Function not running correctly - python

Trying to implement a program in Python that can check if the input is a valid credit card and display the credit card type(VISA/MASTERCARD/AMEX). For 2 values it's displaying incorrectly and for 2 days I have no ideas how to fix it ?
Output received:( last 2 are incorect 4111111111111113 and 4222222222223) I guess is something related with the check_last_digit function ....
identifies 378282246310005 as AMEX
:) identifies 371449635398431 as AMEX
:) identifies 5555555555554444 as MASTERCARD
:) identifies 5105105105105100 as MASTERCARD
:) identifies 4111111111111111 as VISA
:) identifies 4012888888881881 as VISA
:) identifies 4222222222222 as VISA
:) identifies 1234567890 as INVALID
:) identifies 369421438430814 as INVALID
:) identifies 4062901840 as INVALID
:) identifies 5673598276138003 as INVALID
:( **identifies 4111111111111113 as INVALID**
**expected "INVALID\n", not "VISA\n\n"**
:( **identifies 4222222222223 as INVALID**
**expected "INVALID\n", not "VISA\n\n**
My Code:
#function to find out the sum of every other numbers from the input card
def odd_sum(num):
num = list(str(num))
my_list_digits = [int(item) * 2 for item in num][::2]
total_odd = 0
for number in my_list_digits:
if number > 9:
first_digit = number // 10
second_digit = number % 10
total_odd += first_digit + second_digit
else:
total_odd += number
return total_odd
# function to find out the sum of the other remaining numbers
def even_sum(num):
num = list(str(num))
del num[::2]
my_list_digits1 = [int(item) for item in num]
total_even = 0
for item in my_list_digits1:
total_even += item
return total_even
# function to check the lenght of the input card
def check_length(num):
num = str(num)
num_length = len(num)
if 13 <= num_length <= 16:
return True
else:
print("INVALID")
# function to check the last digit of the sum ( even and odd)
def check_last_digit(num):
odd = odd_sum(num)
even = even_sum(num)
if (odd + even) % 10 == 0:
return True
else:
return False
# function to determine the type of card that was provided
def card_type(card_num):
card_num = str(card_num)
AMEX = ["34", "37"]
MASTERCARD = ["51", "52", "53", "54", "55"]
VISA = ["4"]
if (card_num[0:2]) in AMEX:
print("AMEX")
elif (card_num[0:2]) in MASTERCARD:
print("MASTERCARD")
elif (card_num[0]) == VISA[0]:
print("VISA\n")
else:
print("INVALID")
# main program to run all the above created functions
def main():
#get input from user
card_num = int(input("CARD: "))
#check if the bellow 2 functions are True and if so, run the card type function so we can see what type of card was usde(visa, mastercard,amex)
if check_length(card_num):
card_type(card_num)
else:
if check_last_digit(card_num):
card_type(card_num)
main()

It looks like in your main function
#check if the bellow 2 functions are True and if so, run the card type function so we can see what type of card was usde(visa, mastercard,amex)
if check_length(card_num):
card_type(card_num)
else:
if check_last_digit(card_num):
card_type(card_num)
is supposed to check that both check_length and check_last_digit are passed. However, in your code, if check_length returns True, then the second check is not ran. You need to change your code to make sure that both test are run:
def main():
#get input from user
card_num = int(input("CARD: "))
#check if the bellow 2 functions are True and if so, run the card type function so we can see what type of card was usde(visa, mastercard,amex)
if check_length(card_num) and check_last_digit(card_num):
card_type(card_num)
else:
print("INVALID")
Edit:
There are two other errors in your implementation of the Luhn algorithm.
The odd_sum function is supposed to sum every other digit, starting from the right-most one, and skipping one, but your implementation sums the wrong digits if the number of digits of the input number is odd. To correct for that, you should, for instance, reverse the list first:
l = [int(item) * 2 for item in num[::-1]]
then, remove the first digit (the rightmost one)
l = l[1:]
and finally, take every other digit:
my_list_digits = l[::2]
Then, there's a similar error in even_sum, you should also consider reversing the list, to make sure to consider the correct digits:
my_list_digits1 = [int(item) for item in num[::-1]]
return sum(my_list_digits1)
Lastly, as Jakob mentioned, you should return False instead of "INVALID" in your check_length function.
As a refactoring tip, if you see yourself writing
if condition:
return True
else:
return False
then you can refactor that in the cleaner:
return condition
So for instance:
def check_last_digit(num):
odd = odd_sum(num)
even = even_sum(num)
return (odd + even) % 10 == 0:

Related

How to process credit card input string according to the following conditions with python

I have a credit card company ABC which issues credit card numbers based on the following rules:
1. The number must contain exactly 16 digits
2. The input string must not have any other character apart from hyphen as separator
3. The input may contain four number groups separated by a hyphen e.g 5122-2368-7954- 3214
4. The input must not have 4 or more repeated numbers
5. The input must start with either 4 , 5 or 6
I wrote python code to get an input from a user and process it according to the conditions above, if string satisfies all the requirements above then the code should output "Valid" else it should print "Invalid"
Input Format
My first input line takes the number of input strings the program is to take from the user. For example if user wants to pass string input four times, he would pass 4 as an input for this first line.
##take input for number of test cases user wants to run
T=int(input())
The next T lines contain the credit card number input needed for the program to process. My code has been broken down into how I tried to tackle each step declared above, if string fails a single condition then we ignore the body of our loop and skip to the next iteration to process the next user string.
for r in range(T):
##read current credit card string from user
credit=input()
##step 1
##check if the string has a minumum of 16 digits
digit_count=0
for el in credit:
if(el.isdigit()):
digit_count+=1
##check and skip to next iteration if false after Invalid output
if(digit_count!=16):
print("Invalid")
continue
##If this string does have a hyphen then we have to make sure the other
if('-' in credit):
##check and make sure that te hyphen indices do not have a non hyphen character
if(credit[4]!='-' or credit[9]!='-' or credit[14]!='-'):
##print invalid and go to the next iteration
print("Invalid")
continue
##also make sure the hyphen split the input into a group of four numbers
if(len(credit.split("-")!=4):#this operation should create an array of four members
print("Invalid")
continue
##continuing to processs input not having 4 or more repeated characters
##remove the hyphens first from the input
pure_nos=credit.replace("-","")
##compare length of set of pure_nos against the length of pure_nos
if(len(pure_nos)-len(set(pure_nos))>=4):
print("Invalid")
continue
##make sure the first character is either a 4 , 5 or 6
if(credit[0]!='4' or credit[0]!='5' or credit[0]!='6'):
print("Invalid")
continue
##if a string passes all the above then it must be valid
print("Valid")
The input strings I am using
Foreach iteration i pass the values below as input in that order downwards
6
4123456789123456
5123-4567-8912-3456
61234-567-8912-3456
4123356789123456
5133-3367-8912-3456
5123 - 3567 - 8912 - 3456
Output
My code returns Invalid for all test cases , please help me correct this.
I would take a slighly different approach. First refactor your check into a function: Now you can return if the credit is valid or not and don't have to work with many continues.
First I would process the numbers in the credit card:
numbers = ""
for number in credit:
# ignore spaces
if number == " ":
continue
# we found a "-".
# Now check if the length of numbers is divisible by 4
if number == "-" and len(numbers) % 4 == 0:
continue
# not a number
# (Note that "-" and " " are also valid because
# of the continue)
if not number.isdigit():
return False
# add the number to all numbers
numbers += number
Now you can check their length:
if len(numbers) != 16:
return False
After that check the repetition:
For each number in the credit card, check if any of the following 3 numbers is not equal
# iterate over all numbers but not the last three
# because if a repetition would start there
# it would be to small
for i in range(len(numbers) - 3):
repetition = True
# check each of the next three characters
for j in range(1, 4):
# we have found a different number,
# so there is no repetition here
if numbers[i] != numbers[i+j]:
repetition = False
if repetition:
return False
Last check the first character:
if credit[0] not in "456":
return False
Full code of check function:
def check_credit(credit):
# process numbers
numbers = ""
for number in credit:
if number == " ":
continue
if number == "-" and len(numbers) % 4 == 0:
continue
if not number.isdigit():
return False
numbers += number
# check length
if len(numbers) != 16:
return False
# check for repetition
for i in range(len(numbers) - 3):
repetition = True
for j in range(1, 4):
if numbers[i] != numbers[i+j]:
repetition = False
if repetition:
return False
# check first character
if credit[0] not in "456":
return False
return True
Additionally I added a function to test the check function with your testcases (assert throws an exception if the value behind it is not truthy):
def test():
assert check_credit("4123456789123456")
assert check_credit("5123-4567-8912-3456")
# invalid: group of five
assert not check_credit("61234-567-8912-3456")
assert check_credit("4123356789123456")
# invalid: repetition
assert not check_credit("5133-3367-8912-3456")
assert check_credit("5123 - 3567 - 8912 - 3456")
And last I added a function to get the user input as you did in your question:
def user_input():
# note that variables in python should be lowercase
t = int(input())
for r in range(t):
credit = input()
if check_credit(credit):
print("Valid")
else:
print("Invalid")

Luhns Algorithm, mod 10 check

I have to make an assignment for my course computational thinking, but when I give this valid credit card number as input it keeps saying that the number is invalid, does anyone know why??
def ask_user():
string = (str(input("Please input your credit card number")))
numbers = list(map(int, string.split()))
if card_length(numbers):
validation(numbers)
else:
print("The credit card number you entered is invalid")
"""
This function takes the credit card number as a parameter and checks the length of the credit card number
to see if it is valid or not.
"""
def card_length(numbers):
for i in numbers:
if 13 <= i <= 16:
if numbers[0] == 4 or numbers[0] == 5 or numbers[0] == 6 or (numbers[0] == 3 and numbers[1] == 7):
return True
else:
return False
"""
This method takes the list of numbers and tells the user if it is a valid combination with a print statement
"""
def validation(numbers):
odd_results = odd_digits(numbers)
even_results = even_digits(numbers)
sum_of_results = odd_results + even_results
if sum_of_results % 10 == 0:
print("This credit card number is valid")
else:
print("This credit card number is invalid")
"""
This function takes the credit card number as a string list parameter and adds all
of the even digits in it.
"""
def even_digits(numbers):
length = len(numbers)
sumEven = 0
for i in range(length - 2, -1, -2):
num = eval(numbers[i])
num = num * 2
if num > 9:
strNum = str(num)
num = eval(strNum[0] + strNum[1])
sumEven += num
return sumEven
"""
This function takes the credit card number as a string list parameter and adds all
of the odd digits in it.
"""
def odd_digits(numbers):
length = len(numbers)
sumOdd = 0
for i in range(length - 1, -1, -2):
numbers += sumOdd
return sumOdd
"""
This is the main function that defines our first function called ask_user
"""
def main():
ask_user()
if __name__ == '__main__':
main()
The split() method returns a list of strings after breaking the given string by the specified separator.
Syntax : str.split(separator, maxsplit)
separator : This is a delimiter. The string splits at this specified separator. If is not provided then any white space is a separator.
maxsplit : It is a number, which tells us to split the string into maximum of provided number of times. If it is not provided then there is no limit.
Since you are taking the credit card number as a string without any spaces between the numbers, on splitting the credit card number you will get a list which contains the entire credit card number as a single element of the list(numbers). Therefore, the length of the numbers list will always be one and the card length function will always return False. I suggest you do something like:
string = (str(input("Please input your credit card number")))
numbers = list(map(int, list(string)))
Moving on, let me explain how the Luhn algorithm works:
The last digit in the number is taken as checksum. Alternate numbers starting from the number
next(on the left) to the checksum digit are doubled. If the number becomes a double digit on doubling
then the individual digits are added: 14 --> 1+4 = 5 (or) we could also subtract 9 from the digit
which would give us the same answer: 14-9 =5. All the digits(excluding the checksum digit) are now
added. The sum of these digits is multiplied by 9 and the mod 10 of the number is taken. If the
result of the mod 10 of the number is equal to the checksum digit, then the number is valid.
This is one of the ways in which you could write the code for the algorithm:
card_number = list(map(int, list(input('Enter the credit card number : '))))
card_number.reverse()
checksum = card_number.pop(0)
for i in range(len(card_number)):
if i % 2 == 0:
x = card_number[i] * 2
if len(str(x)) == 2:
x -= 9
card_number[i] = x
total = sum(card_number) * 9
total %= 10
if total == checksum:
print('It is a valid number')
else:
print('It is not a valid number')

I got stuck on this exercise can't figure the True/False part

I got some homework to do and I got stuck with this code. I have no idea how to continue.
This is what I'm suppose to do:
generate_sequence - Will generate a list of random numbers between 1 to 101. The list
length will be difficulty.
get_list_from_user - Will return a list of numbers prompted from the user. The list length
will be in the size of difficulty.
is_list_equal - A function to compare two lists if they are equal. The function will return
True / False.
play - Will call the functions above and play the game. Will return True / False if the user
lost or won.
(Sorry for copy/pasting. My English is not so good.)
import random
difficulty = 101
secret_number = 6
def generate_number():
global secret_number
secret_number = random.randint(0, difficulty)
def get_guess_from_user():
return input( "Please choose number between 1 to " + str(difficulty))
def compare_results(userInput):
isSame = False
if(secret_number == userInput):
isSame = True
return isSame
def play():
generate_number()
userInput = get_guess_from_user()
isSame = compare_results(userInput)
print("number generated is: " + str(secret_number))
print(isSame)
play()
Your "problem" is, that if(secret_number == userInput): is currently comparing an int to a str, because the result of input() is always a str, even if the input is numeric. An int and a str are never equal, thus isSame will always be False.
You have to cast the user input to int somewhere along the way before or during the comparison.
e.g.:
def get_guess_from_user():
return int(input( "Please choose number between 1 to " + str(difficulty)))
# ^^^
Otherwise, your program seems to do what you are describing.
You could save some lines of code by writing:
def compare_results(userInput):
return (secret_number == userInput)
I took the liberty to rewrite your application w/o global variables:
import random
def generate_number(difficulty):
return random.randint(1, difficulty)
def get_guess_from_user(difficulty):
return int(input( "Please choose number between 1 to {}".format(difficulty)))
def play(difficulty):
secret_number = generate_number(difficulty)
user_input = get_guess_from_user(difficulty)
is_same = (secret_number == user_input)
print("number generated is: {}".format(secret_number))
print("Your guess was {}".format( "correct :)" if is_same else "not correct :(" ))
play(5)
Note: I also changed random.randint(0, difficulty) to random.randint(1, difficulty), because the lower part is also inclusive, meaning that it could return 0. When prompting the user for a number between 1 and 5, the user might be surprised that the correct number was 0 instead.
See the docs:
random.randint(a, b)
Return a random integer N such that a <= N <= b. Alias for randrange(a, b+1).

How to multiply every other list item by 2 in python

I'm making a program that validates a credit card, by multiplying every other number in the card number by 2; after i'll add the digits multiplied by 2 to the ones not multiplied by 2. All of the double digit numbers are added by the sum of their digits, so 14 becomes 1+4. I have a photo below that explains it all. I'm making a python program that does all of the steps. I've done some code below for it, but I have no idea what to do next? Please help, and it would be greatly appreciated. The code I have returns an error anyway.
class Validator():
def __init__(self):
count = 1
self.card_li = []
while count <= 16:
try:
self.card = int(input("Enter number "+str(count)+" of your card number: "))
self.card_li.append(self.card)
#print(self.card_li)
if len(str(self.card)) > 1:
print("Only enter one number!")
count -= 1
except ValueError:
count -= 1
count += 1
self.validate()
def validate(self):
self.card_li.reverse()
#print(self.card_li)
count = 16
while count >= 16:
self.card_li[count] = self.card_li[count] * 2
count += 2
Validator()
To perform that sum:
>>> s = '4417123456789113'
>>> sum(int(c) for c in ''.join(str(int(x)*(2-i%2)) for i, x in enumerate(s)))
70
How it works
The code consists of two parts. The first part creates a string with every other number doubled:
>>> ''.join(str(int(x)*(2-i%2)) for i, x in enumerate(s))
'8427226410614818123'
For each character x in string s, this converts the character to integer, int(x) and multiplies it by either 1 or 2 depending on whether the index, i, is even or odd: (2-i%2). The resulting product is converted back to a string: str(int(x)*(2-i%2)). All the strings are then joined together.
The second part sums each digit in the string:
>>> sum(int(c) for c in '8427226410614818123')
70
You need to increment the count inside the while() loop. Also, append the user input to your card_li list after you have the if.. check. Your init method should look like:
def __init__(self):
count = 1
self.card_li = []
while count <= 16:
try:
self.card = int(input("Enter number "+str(count)+" of your card number: "))
if len(str(self.card)) > 1:
print("Only enter one number!")
self.card_li.append(self.card)
count += 1
except ValueError:
pass
self.validate()
As for your validate method, it doesn't seem complete even according to the logic you have written.

Using random.randint help in python

The following code is my attempt at simulating a lottery.
import random
def lottery(numbers):
lottoNumbers = [randint('0,100') for count in range(3)]
if numbers == lottoNumbers:
print('YOU WIN $10,000')
else:
print('YOU LOSE,DUN DUN DUNNN!')
return numbers
def main():
numbers = int(input('Enter a number: '))
if numbers == lottoNumbers:
numbers = lottery(numbers)
else:
numbers = lottery(numbers)
main()
Hey guys I've gotten this far with the help you've given me. I'm trying to write the code so that 3 lotto numbers at random will be chosen. Then the user must enter 3 of his/her own lotto numbers. If they get all 3 correct then they win the whole prize, if they get the 3 numbers but not in the correct order they win some of the prize. Obviously if they guess all wrong then a print statement would state that. What I'm confused about is how can I write the code so that the user can enter 3 numbers to try matching the random lottery numbers. I also want to print the 3 lottery numbers after the user inputs his/her choices. Any ideas guys?
Thanks for your help everyone.
You seem a bit confused about what the role of the arguments in a function are. You've said that your randm function takes the argument "number", but then you haven't actually used it anywhere. The next time number appears, you've assigned it a completely new value, so any value passed to randm isn't actually being used.
Also, the function is trying to return x, when x hasn't been assigned within the function. Either you already have a global variable called x already defined, in which case the function will just return that variable, or the function will just fail because it can't find the variable x.
Here's a quick example I've done where you pass their three numbers as a list as an argument to the function.
import random
theirNumbers=[5,24,67]
def checkNumbers(theirNumbers):
lottoNumbers = []
for count in range(3)
lottoNumbers.append(random.randint(0,100))
winning = True
for number in theirNumbers:
if not each in lottoNumbers: winning=False
if winning == True: print("Winner!")
There are a few things wrong with your implementation, to name a few:
if you are trying to compare the output of the function randm to x, you will need to include a return value in the function, like so:
def randm():
return return_value
You appear to be printing all the values but not storing them, in the end you will only end up with the final one, you should attempt to store them in a list like so:
list_name = [randint(0,100) for x in range(x)]
This will generate randint(0,100) x times in a list, which will allow you to access all the values later.
To fix up your code as close to what you were attempting as possible I would do:
import random
def randm(user_numbers):
number = []
for count in range(3):
number.append(random.randint(0, 100))
print(number)
return user_numbers == number
if randm(x):
print('WINNER')
If you are looking for a very pythonic way of doing this task,
you might want to try something like this:
from random import randint
def doLotto(numbers):
# make the lotto number list
lottoNumbers = [randint(0,100) for x in range(len(numbers))]
# check to see if the numbers were equal to the lotto numbers
if numbers == lottoNumbers:
print("You are WinRar!")
else:
print("You Lose!")
I'm assuming from your code (the print() specifically) that you are using python 3.x+
Try to post your whole code. Also mind the indentation when posting, there it looks like the definition of your function would be empty.
I'd do it like this:
import random
def lottery():
win = True
for i in range(3):
guess = random.randint(1,100)
if int(raw_input("Please enter a number...")) != guess:
win = False
break
return win
Let so do this in few steps.
First thing you should learn in writing code is to let separate pieces of code( functions or objects) do different jobs.
First lets create function to make lottery:
def makeLottery(slotCount, maxNumber):
return tuple(random.randint(1,maxNumber) for slot in range(slotCount))
Next lets create function to ask user's guess:
def askGuess(slotCount, maxNumber):
print("take a guess, write {count} numbers separated by space from 1 to {max}".format(count = self.slotCount, max = self.maxNumber))
while True: #we will ask user until he enter sumething suitable
userInput = raw_input()
try:
numbers = parseGuess(userInput,slotCount,maxNumber)
except ValueError as err:
print("please ensure your are entering integer decimal numbers separated by space")
except GuessError as err:
if err.wrongCount: print("please enter exactly {count} numbers".format(count = slotCount))
if err.notInRange: print("all number must be in range from 1 to {max}".format(max = maxNumber))
return numbers
here we are using another function and custom exception class, lets create them:
def parseGuess(userInput, slotCount,maxNumber):
numbers = tuple(map(int,userInput.split()))
if len(numbers) != slotCount : raise GuessError(wrongCount = True)
for number in numbers:
if not 1 <= number <= maxNumber : raise GuessError(notInRange = True)
return numbers
class GuessError(Exception):
def __init__(self,wrongCount = False, notInRange = False):
super(GuessError,self).__init__()
self.wrongCount = wrongCount
self.notInRange = notInRange
and finally function to check solution and conratulate user if he will win:
def checkGuess(lottery,userGuess):
if lottery == userGuess : print "BINGO!!!!"
else : print "Sorry, you lost"
As you can see many functions here uses common data to work. So it should suggest you to collect whole code in single class, let's do it:
class Lottery(object):
def __init__(self, slotCount, maxNumber):
self.slotCount = slotCount
self.maxNumber = maxNumber
self.lottery = tuple(random.randint(1,maxNumber) for slot in range(slotCount))
def askGuess(self):
print("take a guess, write {count} numbers separated by space from 1 to {max}".format(count = self.slotCount, max = self.maxNumber))
while True: #we will ask user until he enter sumething suitable
userInput = raw_input()
try:
numbers = self.parseGuess(userInput)
except ValueError as err:
print("please ensure your are entering integer decimal numbers separated by space")
continue
except GuessError as err:
if err.wrongCount: print("please enter exactly {count} numbers".format(count = self.slotCount))
if err.notInRange: print("all number must be in range from 1 to {max}".format(max = self.maxNumber))
continue
return numbers
def parseGuess(self,userInput):
numbers = tuple(map(int,userInput.split()))
if len(numbers) != self.slotCount : raise GuessError(wrongCount = True)
for number in numbers:
if not 1 <= number <= self.maxNumber : raise GuessError(notInRange = True)
return numbers
def askAndCheck(self):
userGuess = self.askGuess()
if self.lottery == userGuess : print "BINGO!!!!"
else : print "Sorry, you lost"
finally lets check how it works:
>>> lottery = Lottery(3,100)
>>> lottery.askAndCheck()
take a guess, write 3 numbers separated by space from 1 to 100
3
please enter exactly 3 numbers
1 10 1000
all number must be in range from 1 to 100
1 .123 asd
please ensure your are entering integer decimal numbers separated by space
1 2 3
Sorry, you lost
>>> lottery = Lottery(5,1)
>>> lottery.askAndCheck()
take a guess, write 5 numbers separated by space from 1 to 1
1 1 1 1 1
BINGO!!!!

Categories

Resources