How do you handle multi digit numbers in Python? - python

I want to write a function that checks if a syntax is correct. The part of the syntax I struggle with is this one:
< number >: := 2 | 3 | ...
I have defined it as:
def number(q):
letter = q.dequeue()
if int(letter) >= 2:
return
raise error("Number must be greater than 2")
Where the input is q (Linked queue) containing characters. What this
function is supposed to do is check whether the integer in the input is greater than two. The integers could be "2","100", "12" and so on. However, what I think my function does is it only looks for the first integer that comes up in the input and that's why It doesn't work the way it's supposed to.
The way it's supposed to work: if the function finds a "0" in the beginning of the input(ex:H010) it should give the error "Number must be greater than 2". But for every other case, if the digits start with anything that isn't "0" the function should read through every digit of the input before deciding if the number is bigger or smaller than two.
If I were to write the input "H122", the function should be able to read the whole number "122" and and not only the first which is "1".
My question is, how do I make this work?

Assuming you get the entire string, you can do it this way:
def validate(q):
word = q.dequeue()
if word[0] != 'H':
raise error("Does not start with H.")
if not word[1:].isdigit():
raise error("Value is not numeric.")
val = int(word[1:])
if val < 2:
raise error("Number must be greater than or equal to 2.")
return val

I'm not entirely sure about what type q is, or what the H in the string represents for example, but this should work for the cases outlined in the question:
def number(q):
nums = filter(str.isdigit, q)
try:
first_num = next(nums)
except StopIteration:
raise error('Enter a string with numbers')
if first_num == '0':
raise error("Number must be greater than 2")
return int(''.join([first_num, *nums]))
# raises errors
# number('abc')
# number('H012')
assert number('abc123') == 123
assert number('aaaaah123heeeellllpp45') == 12345
assert number('H122') == 122
assert number('2') == 2
assert number('100') == 100

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")

Python: Credit Card digits verification

I need to implement a function called “verify” that takes a single parameter called “number” and then checks the following rules:
The first digit must be a 4.
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 ####-####-####.
The sum of all digits must be evenly divisible by 4.
4 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
This is what I have come up with so far:
def verify(number) : # do not change this line!
# write your code here so that it verifies the card number
number_string = number.replace("-","")
cardnumber = [int(n) for n in number_string]
if cardnumber[0] != 4:
return 1
elif cardnumber[3] != cardnumber[4] + 1:
return 2
elif sum(map(int, cardnumber)) % 4 != 0:
return 3
elif cardnumber[0:2] + cardnumber[6:8] != 100:
return 4
return True
# be sure to indent your code!
input = "4002-1001-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!
You seem to have forgotten that you already converted cardnumber to a list of integers. It's not a string any more, so you don't need to use int each and every time. To compute your sums, you just need cardnumber[0]*10+cardnumber[1] and cardnumber[7]*10+cardnumber[8].
cardnumber is a list. A list can not be converted to an integer. To do so, you first need to convert the list to a string and to integer or directly to an integer using some logic.
using string to integer logic
elif int(''.join(cardnum[0:2])) + int(''.join(cardnum[7:9])) != 100:

Converting binary to decimal only using basic functions len(), ord(), print(), etc

I'm trying to create a scientific calculator for an assignment. I'm looking for a bit of help with python syntax, and I think my design and pseudo code are doing well, but for whatever reason python isn't having any of my syntactical issues. Here is the code I have for converting binary to decimal.
I need the code to reprompt when the input is invalid, but when it does reprompt, it gets stuck in a loop of reprompting and won't give me any way out.
def bintodec(var):
power = (len(var) + 1)
value = ' '
while True:
var = input('Give a number to convert from binary to decimal: ')
for x in range(len(var)):
if (ord(var[x]) == 49):
power -= 1
value += x * (2 ** power)
if (ord(var[x]) == 48):
power -= 1
value += x * (2 ** power)
if power == -1:
break
else:
boo = True
return value
Any help is greatly appreciated!
This is pretty classic. Reading in a base is easier than writing in one.
def bintodec(var):
assert set(var) <= set("01") # Just check that we only have 0s and 1s
assert isinstance(var, str) # Checks that var is a string
result = 0
for character in var: # character will be each character of var, from left to rigth
digitvalue = ord(character) - ord("0")
result *= 2
result += digitvalue
return result
Ok, how does it work ?
Well, it reads the value from left to right. digitvalue will contain 1 or 0. For each digit we read, if it is 0, there is nothing to add the result (so result += digitvalue adds indeed 0), but we still need take into account that there is one more 0 at the end of the number.
Now, in base 10, adding a zero to the end makes a number 10 times as big. This is the same in base 2. Adding a zero at the end makes a number twice as big. This is why we multiply it by 2.
Finally, if digitvalue is 1 instead of 0, we need to add 1 to the number and result += digitvalue does it.
Note: Just for things to be clear, the two for loops below are equivalent.
for character in var:
pass # pass does nothing
for i in range(len(var)):
character = var[i]
pass
#JayF.:
Is there any way to reprompt without using assert?
I suppose you want to reprompt if the input is incorrect. You need to use a loop for that:
while True:
var = input()
if set(var) <= set("01"):
print(bintodec(var))
break # Remove this `break` statement if you want to reprompt forever
else:
# print("The input must consist of only 0s and 1s.")
pass # `pass` does nothing.
If you leave the asserts in the bintodec function, it can be done in a more pythonic way, using exception handling:
while True:
var = input()
try:
print(bintodec(var))
break
except AssertionError:
print("The input must consist of only 0s and 1s.")

How to get only numbers as a response in python?

I'm very new to python, in fact, to programming in general. I'm trying to do a program that compares three numbers and determines which one is smaller. I got the code done, but now i need to make it only accept numbers, and still running when it finds a literal value. For example, code will be ok if you put any number, but when you type a string value it crashes. here is the code
num1=0;
num2=0;
num3=0;
num1=int((raw_input("Type below the first number \n")));
num2=int((raw_input("Type below the second number\n")));
num3=int((raw_input("Type below the third number \n")));
if (num1<num2) and (num1<num3):
print "%i is the smallest number of all three"% num1;
elif (num2<num1) and (num2<num3):
print "%i is the smallest number of all three"% num2;
elif (num3<num2) and (num3<num1):
print "%i is the smallest number of all three"% num3;
elif (num1==num2) or (num1==num3) or (num2==num3):
print "Two equal numbers have been written.";
A simple while loop. You may put this in a function.
while True:
try:
num1=int((raw_input("Type below the first number \n")))
break
except ValueError: # catch the *specific* exception
print("Enter numbers only")
Read more on exceptions:
Handling Exceptions in Python
The most important point is probably to separate concerns, ie. keeping user input separate from validation. You've gotten a couple of good solutions using exceptions. Here is a solution that manually validates the input:
def is_int(strval):
"""A string represents an int if all characters are digits.
Returns True if strval represents a valid int, otherwise False.
"""
for ch in strval:
if not ch.isdigit(): # if '0' <= ch <= '9':
return False
return True
def read_int(prompt='Type number: '):
"""Read one integer from user.
"""
while True:
val = raw_input(prompt)
if is_int(val):
return int(val, 10) # the 10 is the radix (base)
else:
print 'That is not a number.., try again'
numbers = []
for pos in 'first', 'second', 'third':
numbers.append(read_int('Type %s number: ' % pos))
to use the exception handling code, all you have to do is change is_int:
def is_int(strval):
try:
int(strval, 10)
except ValueError:
# int() raised an exception, so strval is not an int
return False
else:
# int() didn't raise an exception, so it is an int
return True
it is also possible to be a bit more concise when finding the smallest:
def smallest(a, b, c):
if b > a < c: # if a is less than both b and c..
return a
if a > b < c:
return b
if a > c < b:
return c
return "Error: two of the numbers must be equal!"
you can call it like so:
smallest(numbers[0], numbers[1], numbers[2])
but Python has a shorthand that does exactly that which looks like:
smallest(*numbers)
def getNumber(i):
try:
num = int(raw_input("type in number %s : " %i))
return num
except Exception as e:
print('This is not a valid number')
return getNumber(i)
numbers = []
for i in range(1,4):
numbers.append(getNumber(i))
print(numbers)
You can simply add the input getting code in try except block and handle the ValueError exception with some meaningful code.
try:
num1=int((raw_input("Type below the first number \n")));
num2=int((raw_input("Type below the second number\n")));
num3=int((raw_input("Type below the third number \n")));
except ValueError:
print "Please enter integer only."
exit(-1)

For loop utilizing != for string character not working in Python

I am a beginner learning Python 3.4, and am working on a program where I read bits from the user, and determine the parity bit based on an even parity.
I am doing a check to see if the user enters the correct 8 bits, and if they are entering 1 or 0 only.
The user is entering the value using the input() function, and is entered as a string. My error comparison function is as follows:
#Check for errors in user defined string
def errors(check):
for i in check:
if (i != '1' or i != '0') and len(check) == 8:
result = 0 #return value means not binary, but right amount of digits
#break
elif (i != '1' or i != '0') and len(check) != 8:
result = 1 #Not binary and wrong amout of digits
break
elif len(check) != 8:
result = 2 #wrong amount of digits but binary
break
elif (i == '1' or i == '0'):
result = 3 #Binary, and correct amount of digits
else:
print('Error checking loop messed up')
return result
basically my first if statement is executing (even though I am entering in 10101010), or my second if statement (101010101010, or 1010ag1010 something like that).
my output is as follows:
enter a string of bits (must be 1 or 0, max. 8): 10101010
You entered a value that is not a 1 or 0
The program is not recognizing my 1's and 0's for some reason. Any help to point me in the right direction would be much appreciated.
First of all , the first if condition is wrong -
if (i != '1' or i != '0') and len(check) == 8:
Why? Because lets say i is 1 so in first part of the condition , we see that i is not equal to 0 , so it is True, and in second part if check is equal to 8 , we enter the if condition.
It should ideally be an and -
if (i != '1' and i != '0') and len(check) == 8:
Similarly, use and in second condition as well.
But given that, I think you should ideally consider length of the string and each character being 1 or 0 as completely different and instead return back a list, where one element indicates whether the length of the array is correct or not, and the second element indicates whether the characters are all 1 and 0 or not.
Example -
def errors(check):
result = []
if len(check) == 8:
result.append(1)
else:
result.append(0)
for i in check:
if i not in {'1','0'}:
result.append(0)
break
else:
result.append(1)
return result
Then you can compare against this list in your main code (or wherever you call the function from, and decide what all were wrong).
It would return 0 in first element if length is wrong, 1 otherwise.
It would return 1 in second element if all characters are either 1 or 0 , 0 otherwise.

Categories

Resources