Validate Credit Card Number Using Luhn Algorithm Python - python

I am trying to implement Luhn algorithm in Python. Here is my code
def validate(n):
if len(str(n)) > 16:
return False
else:
if len(str(n)) % 2 == 0:
for i in str(n[0::2]):
digit = int(str(n[i])) * 2
while digit > 9:
digit = sum(map(int, str(digit)))
dig_sum = sum(map(int, str(n)))
return True if dig_sum % 10 == 0 else False
elif len(str(n)) % 2 != 0:
for i in str(n[1::2]):
digit = int(str(n[i])) * 2
while digit > 9:
digit = sum(map(int, str(digit)))
dig_sum = sum(map(int, str(n)))
return True if dig_sum % 10 == 0 else False
I keep getting the error
TypeError: 'int' object has no attribute '__getitem__

Following is python implementation of Lunh Algorith to detect a valid credit card number. Function takes a number as string and return whether its valid credit card or not.
Its based on the steps mentioned in the following link: https://www.codeproject.com/Tips/515367/Validate-credit-card-number-with-Mod-algorithm
Step 1 - Starting with the check digit double the value of every other digit (right to left every 2nd digit)  
Step 2 - If doubling of a number results in a two digits number, add up the digits to get a single digit number. This will results in eight single digit numbers.
Step 3 - Now add the un-doubled digits to the odd places
Step 4 - Add up all the digits in this number
If the final sum is divisible by 10, then the credit card number is valid. If it is not divisible by 10, the number is invalid. 
def luhn(ccn):
c = [int(x) for x in ccn[::-2]]
u2 = [(2*int(y))//10+(2*int(y))%10 for y in ccn[-2::-2]]
return sum(c+u2)%10 == 0
#Test
print(luhn("49927398716"))

It is hard to tell without the complete error message, but it is likely because you confused in some places where you put the indexing and where you put the string conversion, for example: for i in str(**n[1::2]**) and digit = int(str(**n[i]**)) * 2
A good way to handle it is to just create a temporary variable n_str = str(n), and use it instead of str(n) over and over again.

Related

how to divide sum of number by digit on number? [duplicate]

This question already has answers here:
Sum the digits of a number
(11 answers)
Write the digits of a number into an array
(4 answers)
Closed 4 months ago.
how to divide num of digit by digit number?
e.g : 4228 is true because 4+2+2+8=16 can divide by 4, 2, 8
3425 false because 3+4+2+5=14 can't divide by 3, 4, 2, 5
numbers = int(input('input number : '))
result = 0
# NUM of digit
while numbers > 0 :
digit = numbers % 10
result = result + digit
numbers = numbers // 10
factors = result
#factors of "NUM of digit"
for factor_result in range(1,factors + 1) :
if factors % factor_result == 0 :
print(factor_result)
please help me;(
thank you a lot:))
A simple way to do it is to calculate the sum of the digits then check if the modulo is 0.
In python, we could parse the number to a str, then convert every digit (which is a single char) back to an int and create a list of these digits
input_numbers = int(input('input number : '))
# parse the number to a str, then map each char back to an integer
# and create a list of int for each digit
numbers = list(map(int, str(input_numbers )))
Now, just use the built-in sum() method to get the result you wish. The next part is just a loop over every digit on the numbers list and check the module.
result = sum(numbers)
is_divisible = True
for number in numbers:
if number == 0 or result % int(number) != 0:
is_divisible = False
print(is_divisible)
From your description it sounds like you want a function like this
# determine if sum of integers comprising an integer is divisible by its part
def divisor_check(num):
# check that input num is integer
if not isinstance(num,int):
print('warning: input is not an integer')
return False
# break num into component integers by convert to string first
stringafied_num = str(num)
# split the string-afied num to get component integers
components = [*stringafied_num]
# evaluate the components to get integers back
components = [eval(v) for v in components]
# sum components
total=sum(components)
# try dividing total by each component
for c in components:
if total%c != 0:
return False
return True
This function breaks up the input into its component integers, sums them, and computes the desired divisor check.
If you evaluate this function for your examples you get the desired results
divisor_check(4228) --> True
divisor_check(3425) --> False
num = 4220
res = [int(x) for x in str(num)]
can_devided = True
for r in res:
if r == 0:
continue
if sum(res) % r != 0:
can_devided = False
print (can_devided)

How to add numbers in a string

Im new to python and i have a homework to validate a credit card number. I finished the first two conditions but Im stucked with #3 and #4 conditions. Any help is appreciated
Conditions:
The first digit must be a 4.- done
The fourth digit must be one greater than the fifth digit; keep in mind that these are separated by a dash since the format is ####-####-####.-done
The sum of all digits must be evenly divisible by 4.-need help
If you treat the first two digits as a two-digit number, and the seventh and eighth digits
as a two-digit number, their sum must be 100.- need help
def verify(number) : # do not change this line!
# write your code here so that it verifies the card number
#condtion 1
if number[0] != '4':
return "violates rule #1"
#condition 2
if int(number[3]) != (int(number[5]) + 1) :
return "violates rule #2"
#condition 3
for i in number:
if i >= '0' and i !='-':
# be sure to indent your code!
return True # modify this line as needed
input = "4037-6000-0000" # change this as you test your function
output = verify(input) # invoke the method using a test input
print(output) # prints the output of the function
# do not remove this line!
Expected outputs:
● "5000-0000-0000": violates rule #1
● "4000-0000-0000": passes rule #1, violates rule #2
● "4007-6000-0000": passes rules #1-2, violates rule #3
● "4037-6000-0000": passes rules #1-3, violates rule #4
● “4094-3460-2754”: passes all rules
For condition #3
Strings in Python are iterable meaning you can pass over them in a for loop. Each element in the loop is a character in the string. So if you did
for char in "4094-3460-2754":
print(char)
You'd get:
4
0
9
4
-
3
4
etc.
Using this, you can calculate the sum of every number in the input and check if it's divisible by 4. Two things to note, you need to convert the characters to integers first (using int). You can't do
"4" + "0"
But you can do
int("4") + int("0")
You'll need to exclude "-" from your sum as well using if.
Second, we check if two numbers are divisible in Python using modulo (%). The result is the remainder, and if the remainder is 0 then the first argument is divisible by the second.
16 % 4 == 0 # divisible by 4
21 % 4 == 1 # not divisible by 4
For condition #4
In addition to being iterable, strings in Python can be accessed by their index (starting at 0)
"4094-3460-2754"[0] == "4"
"4094-3460-2754"[1] == "0"
"4094-3460-2754"[2] == "9"
"4094-3460-2754"[0:1] == "40"
"4094-3460-2754"[1:2] == "09"
So you can access multiple characters and treat them as an integer:
int("4094-3460-2754"[0:1]) == 40
Now you can add them together and see if they equal 100.
For rule 3, you need to sum all the numbers and the check if the remainder on division by 4 is zero:
#condition 3
s = 0
for i in number:
if i != '-':
s += int(i)
if s % 4 != 0:
return "violates rule #3"
For rule 4 you can get the sum of int of substrings:
if (int(number[0:2]) + int(number[7:8])) != 100:
return "violates rule #4"
Full code :
def verify(number) : # do not change this line!
# write your code here so that it verifies the card number
#condtion 1
if number[0] != '4':
return "violates rule #1"
#condition 2
if int(number[3]) != (int(number[5]) + 1) :
return "violates rule #2"
#condition 3
s = 0
for i in number:
if i != '-':
s += int(i)
if s % 4 != 0:
return "violates rule #3"
if (int(number[0:2]) + int(number[7:9])) != 100:
return "violates rule #4"
# be sure to indent your code!
return True # modify this line as needed
input = "4037-6000-0000" # change this as you test your function
output = verify(input) # invoke the method using a test input
print(output) # prints the output of the function
# do not remove this line!
I prefer removing the dashes - from the number first so that it can be easy to work with. You can also do it without removing it like you tried.
# split it into parts separated by dashes
# consider 4094-3460-2754
no_dashes = number.split('-')
print(no_dashes) # ['4094', '3460', '2754']
# combine the numbers without dashes
no_dashes = ''.join(no_dashes)
print(no_dashes) # 409434602754
# convert it into a list of integers so that it is more easier to work with
number = [int(x) for x in no_dashes]
print(number) # [4, 0, 9, 4, 3, 4, 6, 0, 2, 7, 5, 4]
You can read about split() and join() here.
Now, as you mentioned, the first condition is simple and you can simply check if the first number is 4 or not.
# 1st condition
if number[0] != 4:
return 'Violates #1'
The second condition is also simple:
# 2nd condition
# 4th digit is a[3] and 5th digit is a[4]
if number[3] != number[4] + 1:
return 'Viloates #2'
For the third condition, you just have to find the sum of every digit in the number. Since, we already converted the number into an integer array, this is also easy using the sum() function:
# 3rd condition
# Find the sum
num_sum = sum(number)
print(num_sum) # 48
# now check if the sum is divisible by 4
if num_sum % 4 != 0:
return 'Violates #3'
Now, for the fourth condition, you need to treat the 1st & 2nd digit as a two-digit number and same with the 7th and 8th digit. You can convert it into two-digit number as follows:
# 1st digit is number[0]
# 2nd digit is number[1]
# 7th digit is number[6]
# 8ty digit is number [7]
# convert 1st two digits into a two-digit number
x = number[0] * 10 + number[1]
# convert 7th and 8th digits into a two-digit number
y = number[6] * 10 + number[7]
Now you can check if their sum is 100 or not:
if x + y != 100:
return 'Violates #4'
So, the combined program becomes (with some steps merged):
def verify(number):
number = [int(x) for x in ''.join(number.split('-'))]
if number[0] != 4:
return 'Violates #1'
if number[3] != number[4] + 1:
return 'Viloates #2'
if sum(number) % 4 != 0:
return 'Violates #3'
if (number[0] * 10 + number[1] + number[6] * 10 + number[7]) != 100:
return 'Violates #4'
return True
But the above program will only give the 1st condition that fails. You can modify it further if you want as follows:
def verify(number):
failed = []
number = [int(x) for x in ''.join(number.split('-'))]
if number[0] != 4:
failed += [1]
if number[3] != number[4] + 1:
failed += [2]
if sum(number) % 4 != 0:
failed += [3]
if (number[0] * 10 + number[1] + number[6] * 10 + number[7]) != 100:
failed += [4]
res = 'Violates ' + (', '.join[str(x) for x in failed])
return res if len(failed) != 0 else 'Passed'
print(verify('4094-3460-2754')) # Passed
print(verify('4037-6000-0000')) # Violates 4
You can again modify it to display passed conditions too. I leave it upto you!
The sum of all digits must be evenly divisible by 4.
You can check this with a conditional statement like:
if sum_of_nums % 4 != 0:
print("Violates rule 3!")
This checks if there is any remainder when dividing by four, and if there is no remainder it will divide evenly and the expression will equal zero. If it does not divide evenly it will not equal 0!
If you treat the first two digits as a two-digit number, and the seventh and eighth digits as a two-digit number, their sum must be 100.
Here you can reference the characters of a string like you do a list. If the input is always going to be consistent you can hard code the references, change them to ints and then add them together and check them with a conditional statement
first_num = input[0]+input[1]
first_num = int(first_num) #now an int
second_num = input[6]+input[7]
second_num = int(second_num)
if first_num + second_num != 100:
print("Violates rule 4!")

Taking away from nearest 10

Okay, i have made my code so that a user can input 7 numbers and times them by 1 for the odd index numbers and 3 for the even:
num = str(input("Please enter 7 numbers")
length = len(num)
while length < 7 or length ? 7:
num = input("Only enter 7 numbers")
string = ''
for t in range(1,8):
if t % 2 == 0:
string += str(t * 3)
else:
string += str(t) + ' '
print(string)
This works fine, but now i need to add all the numbers up and take it away from the highest 10 so for example, all the numbers add up to 53 i need to take that away from 60 which leaves me 7, that will be my eight number, then after i have got that number i print it out, how do i get it to add the numbers up and the take it away from the highest 10 and output the difference of the two into the numbers i already have?
Thanks
Brad
If you have a number, x, which is equal to 53, then going up should be math.ceil(x) except that math.ceil() rounds for 1. To account for that, we divide by 10, use math.ceil(), and then multiply by 10 again:
import math
rounded_up = math.ceil(x / 10) * 10
result = rounded_up - x
Brad could you clarify your question? Also your above code does not work.
Missing a bracket on the first line and this isn't valid while length < 7 or length ? 7:
I believe this is what you're looking for:
def take_away_from_nearest(number, nearest):
return nearest - (number % nearest)
Usage:
>>> take_away_from_nearest(53, 10)
7
edit:
If I understand you correctly, this would be the entire code:
while True:
# this is just an easy way to keep asking until the input is correct
num = input("Please enter 7 numbers: ")
if len(num) == 7:
break
weird_sum = 0 #here's where we're gonna sum up the numbers; the "eighth number"
for index, character in enumerate(num):
if index % 2 == 0: # index is odd, so count the character thrice
print(3 * int(character))
weird_sum += 3 * int(character)
else: # index is even
print(int(character))
weird_sum += int(character)
print(10 - (weird_sum % 10)) # 10 minus (weird_sum modulo 10)
# and finally, adding them all up and checking whether it ends with 0:
print((10-(weird_sum % 10) + weird_sum) % 10 == 0) # prints True

Luhn checksum method; separating two digits and finding the sum of that list

I am currently trying to use the luhn method to determine whether a credit card is valid or not in python and here is what I have so far:
print('What is your Credit Card number? :) (please put a space between each number)')
a = [int(x) for x in input().split()]
lengthy = len(a)
print(lengthy)
a.reverse()
print(a)
listx2 = []
listx1 = []
for x in range(len(a)):
modulus = x % 2
print(x, a[x])
if modulus != 0:
listx2.append(a[x]*2)
else:
listx1.append(a[x])
print(listx2)
print(listx1)
I don't know how to do the next step which is getting the sum of all of the digits of the numbers multiplied by two.(listx2) I have looked at different programs with the luhn method but I just can't seem to pick that part out. Thanks!
This is my interpretation of the Luhn algo.
def luhn(sequence):
digits = [int(digit) for digit in str(sequence)] # converts a full string of nums to a list comp of individual numbers
odd = digits[-1::-2] # string stepping (-1) indicates last item in list (-2) means to travel back another 2
even = digits[-2::-2]
checksum = 0
checksum += sum(odd)
evenmod = []
for digit in even:
if digit * 2 > 9:
digit = digit * 2
digit = int(str(digit)[0]) + int(str(digit)[1])
else:digit = digit * 2
evenmod.append(digit)
checksum += sum(evenmod)
if checksum % 10 == 0:
return True
else:
return False
print luhn(378282246310005)
print luhn(111111111111111)
print luhn(4751290083628479)
print luhn(5573485043994670)
Separate the even and the odd indeces to separate lists, then use a for statement to loop through the list, multiplying the list entries by two.
Notice the if statement that catches the issue with (e.g) 8 * 2 = 16.
Use sum:
summed_x2 = sum(listx2)

Optimized way for finding the number which satisfies specific conditions

I saw this question somewhere.
There is a 8 digit number. First digit from left to right tells how many zeroes in the number. Second digit tells you how many 1s in the number, third digit tells u how many 2 in the number and so on till 8th digit which tells u how many 7 in the number. Find the number.
So I wrote a piece of code in python to find out the digit. Apart from the conditions mentioned above, I have few additional checks like 'sum of digits should be 8' and 'no 8 or 9 should be present in the number'. I've pasted the code below. This is just brute force since I take every number and check for conditions. I was curious to know if there is any better way of solving the problem
def returnStat(number, digit, count):
number = str(number)
digit = str(digit)
print "Analysing for ",digit," to see if it appears ",count, " times in ",number,"."
actCnt = number.count(digit)
count = str(count)
actCnt = str(actCnt)
if (actCnt == count):
return 1
else:
return 0
def validateNum(number):
numList = str(number)
if '8' in numList:
print "Skipping ",number, " since it has 8 in it"
return (-1)
elif '9' in numList:
print "Skipping ",number, " since it has 9 in it"
return (-1)
elif (sum(int(digit) for digit in numList) != 8):
print "Skipping ",number, " since its sum is not equal to 8"
return (-1)
index = 0
flag = 0
for num in numList:
if (returnStat(number,index,num)) :
index = index+1
continue
else:
flag = 1
break
if (flag == 1):
return (-1)
else:
return number
for num in range(0,80000000):
number = '{number:0{width}d}'.format(width=8,number=num)
desiredNum = "-1"
desiredNum = validateNum(number)
if (desiredNum == -1):
print number," does not satisfy all "
continue
else:
print "The number that satisfies all contition is ",number
break
You can go further than to simply say that digits of 8 or 9 are impossible.
Can the last digit ever be greater than 0? The answer is no. If the last digit was 1, this means there is one 7 somewhere else. However, if there is a 7, it means that the same number has occurred 7 times. This is clearly impossible. Thus the last digit has to be 0.
So we have xxxxxxx0.
What about the second to last digit?
If xxxxxx10, then there has to be at least one 6, which means the same number occurred 6 times. We can try 60000010, but this is incorrect, because there is a 1, which should be reflected in the second digit. The second to last digit can't be higher than 1 because 2 means there are 2 sixes, which in turn means one number occurred six times while another number also occurred 6 times, which is impossible.
So we have xxxxxx00.
If xxxxx100, then there has to be at least one 5, which means the same number occurred 5 times. Let us start with 51000100. Almost, but there are now 2 1s. So it should be 52000100. But wait, there are now one 1. and one 2. So we try 52100100. But now we only have 4 0s. We can't have xxxxx200 because this means there are 2 5s, which is impossible as explained above.
So we have xxxxx000.
If xxxx1000, we can try 40001000, nope, 41001000, nope, 42101000.
Ah there it is. 42101000.
Even if you iterate over all 8 digit numbers with no 8s or 9s in them, there's not many possibilities (actually, 8^8 = 1<<24 ~= 17 million).
Here's a naive program that tries them all:
import itertools
for digs in itertools.product(range(8), repeat=8):
counts = [0] * 8
for d in digs:
counts[d] += 1
if counts == list(digs):
print digs
It completes (with exactly one solution) in 15 seconds on my machine.
To make it faster, you can only consider 8-digit numbers whose digits add up to 8. Here's the same code as before, but now it uses sum_k to produce the possibilities. (sum_k(n, k) generates all n-digit tuples where all the digits are less than 8 which sum to k).
def sum_k(n, k):
if k < 0 or n * 7 < k: return
if n == 1:
yield k,
return
for d in xrange(8):
for s in sum_k(n-1, k-d):
yield (d,) + s
for digs in sum_k(8, 8):
counts = [0] * 8
for d in digs:
counts[d] += 1
if counts == list(digs):
print digs
This code completes in 0.022 seconds on my machine.
Adapting the code to solve the general case produces these solutions:
1210
2020
21200
3211000
42101000
521001000
6210001000
72100001000
821000001000
9210000001000

Categories

Resources