Same input gives different output for a program - python

Novice programmer here. I am trying to write a program wherein it will take UIDs from user and validate them based on certain rules. The rules are:
It must contain at least 2 uppercase English alphabet characters.
It must contain at least 3 digits ( 0-9 ).
3.It should only contain alphanumeric characters (A -Z ,a -z & 0 -9 ).
No character should repeat.
There must be exactly characters in a valid UID.
I am putting in the code. Also apologies for this big code (I am a newbie)
# UID Validation
n=int(input()) #for iterations
uid=[]
# char=[]
valid=1
upper=0
numeric=0
# take input first of everycase
for x in range (0,n):
num=input()
uid.append(num)
# print (uid)
for i in uid:
# print (i)
# to count each word and number
count={}
for char in i:
count[char]=count.get(char,0)+1
for j in i:
if j.isupper():
upper=upper+1
elif j.isnumeric():
numeric=numeric+1
# print('numeric =', numeric)
# print('upper =', upper)
# Check conditions
while valid==1:
if len(i)!= 10:
valid= 0
# print('invalid for word count')
elif i.isalnum()== False: #alphanumeric
valid=0
# print('invalid for alnum')
elif upper<2: #minimum alphabet and numbers
valid=0
# print('invalid for min alphabet')
elif numeric<3:
valid=0
# print('invalid for min numeric')
else:
for k,v in count.items(): #no repitation
if v>1:
valid=0
# to check if given UID is valid or not
if valid==1:
print ('Valid')
elif valid==0:
print('Invalid')
valid=1
break
I have written the code but it seems that I am facing problem on one input only that is to check UID tag: 2TB1YVIGNM
It is an invalid tag. My program shows the same when is I run it alone or first in a batch of many. But, Lets say I run the program and input 2 tags, with "2TB1YVIGNM" being second one, it will show is as "Valid". Mind you, this is only happening in this particular tag
There are several other tags which run fine. Some of them are mentioned here:
77yS77UXtS
d72MJ4Rerf
OA778K96P2
2TB1YVIGNM "EXCEPT THIS TAG"
9JC86fM1L7
3w2F84OSw5
GOeGU49JDw
8428COZZ9C
WOPOX413H2
1h5dS6K3X8
Fq6FN44C6P
The output should be:
Invalid
Valid
Invalid
Invalid
Valid
Invalid
Invalid
Invalid
Invalid
Valid
Invalid
My output is this:
Invalid
Valid
Invalid
Valid
Valid
Invalid
Invalid
Invalid
Invalid
Valid
Invalid

To solve your problem you need to set upper and numeric back to 0 for each uid:
for i in uid:
upper = 0
numeric = 0
count={}
P.S: As for you newbie I would suggest you to read PEP 8 it will make your code more readable and prettier
P.S.S: There is no need to count manually how many times each character meet in string, such operation already implemented in Python look at the Counter for more details
And I agree with comment that for such type of tasks it is better to use regex

You could extract pieces of logic into functions and call them:
#It must contain at least 2 uppercase English alphabet characters.
def has_at_least_two_uppercase(potential_uid):
return sum([char.upper() == char for char in potential_uid])>= 2
#No character should repeat.
def has_unique_chars(potential_uid):
return len(set(potential_uid)) == len(potential_uid)
#There must be exactly characters in a valid UID.
def is_proper_length(potential_uid:str, proper_length:int = 10)-> bool:
return len(potential_uid) == proper_length
#It must contain at least 3 digits ( 0-9 ).
def has_three_digits(potential_uid):
return sum([char.isnumeric() for char in potential_uid])>=3
#It should only contain alphanumeric characters (A -Z ,a -z & 0 -9 )
# Defining a function for this may be an overkill to be honest
def is_alphanumeric(potential_uid):
return potential_uid.isalnum()
def is_valid_uid(potential_uid):
if has_at_least_two_uppercase(potential_uid) is False:
return False
if has_unique_chars(potential_uid) is False:
return False
if is_proper_length(potential_uid) is False:
return False
if has_three_digits(potential_uid) is False:
return False
if is_alphanumeric(potential_uid) is False:
return False
return True
Side notes:
use is to check for True/False
use True/False and not 1/0 for boolean conditions (like valid variable)
[OPTIONAL / homework]
use docstrings instead of comments
add add type hints (see is_proper_length as an example)
you can use all() and pass all the calls into it, but the ifs will short circuit from the function without checking all the conditions (all depends on a problem, like number of conditions, length of the UID, number of UIDs to be checked etc.) and you can play around with order of the checks e.g. if the length is not right there's no need to check the rest (but it's a pre-optimization in a way, which is discouraged in general)
parametrize your functions further if need be, define params for number of upper to check, numeric and so on

Related

How to make this python regex work correctly

I need to validate a number with Python regex, but it is not working.
The code below is a library that is being used by another file. At this point, I am only trying to make the input be the only numbers between 13 and 19 digits. The range works just fine, but when I put a letter into the input, it prints it, instead of giving the "Invalid" string output:
"""
Credit card number validation and provider check
"""
import re
def card_range(cardNumber):
"""
Checks the credit card number length
"""
if len(cardNumber) < 13:
return "Invalid"
if len(cardNumber) > 19:
return "Invalid"
pattern = re.compile("[0-9]+")
if not pattern.match(cardNumber):
return "Invalid"
return cardNumber
You need boundary markers in your regex. But, I would just use a single pattern here:
def card_range(cardNumber):
return re.search(r'^[0-9]{13,19}$', cardNumber)
By the way, regular expressions for the major credit card providers are readily available, e.g. here.
Why not just check using the isnumeric method if the string appears to be a number? Seems like it'll be faster than the regex solution, since we just want to check for a number anyway.
def card_range(cardNumber):
"""
Checks the credit card number length
"""
if not cardNumber.isnumeric():
return 'Invalid! I need only NUMBERZ!'
if not 13 <= len(cardNumber) <= 19:
return "Invalid! The length check FAILED!"
return True
# Invalid! The length check FAILED!
print(card_range('1234567'))
# Invalid! I need only NUMBERZ!
print(card_range('a'))
# True
print(card_range('112233445566778899'))
# Invalid! I need only NUMBERZ!
print(card_range('1122334455x6778899'))

How to use raw_input with no input

I want to use raw_input() function in Python.
I want to receive a number from user about the size of the storage
i wrote this down :
number=raw_input()
if the user doesn't provide an input then number = 10 so
if number is None:
number = 10
when i print number, i get nothing i even tried:
if number==-1:
number=10
print"the storage size was set to:",number
The output was:
>
the storage size was set to -1
and not 10
So how should I solve this ?
If you don't care to distinguish between "no input" and "invalid input" (like a non-integer literal), set the default, then attempt to replace it with the user input.
number = 10
try:
number = int(raw_input())
except (EOFError, ValueError):
pass
ValueError will be raised on invalid inputs, including the empty string. EOFError is raised if the user does something like type Control-d in a terminal that interprets that as closing standard input.
First of all you have to convert the input (default for raw_input is a string) into an int using int() function. But be sure that you first check if user typed something. Otherwise you can't convert an empty string. For example:
num_input = raw_input()
if num_input:
number = int(num_input)
Then already the second part of your question should work:
if number == -1:
number = 10
print "the storage size was set to:", number
The second point is that an empty string is not equal to None. None is the only value of NoneType and "" is a string.
So you can compare the input with an empty string, but you can do better (an empty string is evaluated as False):
if not num_input:
number = 10
and to be even more efficient you can simply add an else statement to my first piece of code:
num_input = raw_input()
if num_input:
number = int(num_input)
else:
number = 10
compare number with empty string; not with None .
if number == '':
number = 10
In Python when the variable is empty then it's have inside empty '',
so if you want to check if your variable is unset you need to compare it to '' and not to None.
if number=='':
number=10
You should just compare number and empty.:
if number=="":
number==10

Nested Loop 'If'' Statement Won't Print Value of Tuple

Current assignment is building a basic text adventure. I'm having trouble with the following code. The current assignment uses only functions, and that is the way the rules of the assignment state it must be done.
def make_selections(response):
repeat = True
while repeat == True:
selection = raw_input('-> ')
for i, v in enumerate(response):
i +=1 # adds 1 to the index to make list indices correlate to a regular 1,2,3 style list
if selection == i:
print v[1]
else:
print "There's an error man, what are you doing?!?!?"
firstResponse = 'You chose option one.'
secondResponse = 'You chose option two.'
thirdResponse = 'You chose option three.'
responses = [(0, firstResponse), (1, secondResponse),( 0, thirdResponse)]
make_selections(responses)
My intention in that code is to make it so if the user selects a 1, it will return firstResponse, if the user selects 2 it will return secondResponse, etc.
I am basically just bug testing the code to make sure it produces the appropriate response, hence the "Error man..." string, but for some reason it just loops through the error message without printing the appropriate response string. Why is this?
I know that this code is enumerating the list of tuples and I can call them properly, as I can change the code to the following and get the expected output:
for i, v in enumerate(response):
i += 1 # adds 1 to the index to make list indices correlate to a regular 1,2,3 style list
print i, v
Also, two quick asides before anyone asks:
I know there is currently no way to get out of this while loop. I'm just making sure each part of my code works before I move on to the next part. Which brings me to the point of the tuples.
When I get the code working, a 0 will produce the response message and loop again, asking the user to make a different selection, whereas a 1 will produce the appropriate response, break out of the loop, and move on to the next 'room' in the story... this way I can have as many 'rooms' for as long of a story as I want, the player does not have to 'die' each time they make an incorrect selection, and each 'room' can have any arbitrary amount of options and possible responses to choose from and I don't need to keep writing separate loops for each room.
There are a few problems here.
First, there's no good reason to iterate through all the numbers just to see if one of them matches selection; you already know that will be true if 1 <= selection <= len(response), and you can then just do response[selection-1] to get the v. (If you know anything about dicts, you might be able to see an even more convenient way to write this whole thing… but if not, don't worry about it.)
But if you really want to do this exhaustive search, you shouldn't print out There is an error man after any mismatch, because then you're always going to print it at least twice. Instead, you want to only print it if all of them failed to match. You can do this by keeping track of a "matched" flag, or by using a break and an else: clause on your for loop, whichever seems simpler, but you have to do something. See break and continue Statements, and else Clauses on Loops in the tutorial for more details.
But the biggest problem is that raw_input returns a string, and there's no way a string is ever going to be equal to a number. For example, try '1' == 1 in your interactive interpreter, and it'll say False. So, what you need to do is convert the user's input into a number so you can compare it. You can do that like this:
try:
selection = int(selection)
except ValueError:
print "That's not a number!"
continue
Seems like this is a job for dictionaries in python. Not sure if your assignment allows this, but here's my code:
def make_selections(response):
selection = raw_input('-> ')
print response.get(selection, err_msg)
resp_dict = {
'1':'You chose option one.',
'2':'You chose option two.',
'3':'You chose option three.'
}
err_msg = 'Sorry, you must pick one of these choices: %s'%sorted(resp_dict.keys())
make_selections(resp_dict)
The problem is that you are comparing a string to an integer. Selection is raw input, so it comes in as a str. Convert it to an int and it will evaluate as you expect.
You can check the type of a variable by using type(var). For example, print type(selection) after you take the input will return type 'str'.
def make_selections(response):
repeat = True
while repeat == True:
selection = raw_input('-> ')
for i, v in enumerate(response):
i +=1 # adds 1 to the index to make list indices correlate to a regular 1,2,3 style list
if int(selection) == i:
print v[1]
else:
print "There's an error man, what are you doing?!?!?"

Python input datatype handling

I spent a good hour or more looking for the answer on here. I have found a few things that help, but do not answer my question specifically. I am using Python 3.3.3. I am a novice so please be gentle.
I am trying to create a program that takes a user input, but then I need to do a check to see what datatype that input is, and then based on that datatype take a certain course of action.
Any string besides those found in this list:
valid_help_string_list = ['\'help\'', '\'HELP\'', 'help', 'HELP']
should result in the printing of:
'please enter a valid entry' or something to that effect.
Any integer (over 0 but under 500) should have float() used on it to make the rows line up.
Any float (over 0.0 but under 500.0) is valid.
For the sake of this project I am assuming nobody using this will weigh under 100 lbs or over 500.
Anything not falling within those categories should also yield the same "please enter a valid response" error message to the user.
I think it's simple enough of a project to take on for a novice. The program is meant to allow you to input your weight and then creates a pictogram based on that weight and saves it all on the next open line of the .txt file I have set up for it. Or if you want to see the legend for the pictogram, you should be able to type help in any variation found in that list.
Any help would be much appreciated.
The user input will be a string by default, so we need to check whether it could become an integer or float. As you want to turn the integers in floats anyway, there's no need to do anything complex:
def validate_input(val, min_v=100, max_v=500):
try:
val = float(val)
except ValueError:
print("Not a valid entry")
else:
if not min_v < val <= max_v:
print("Value should be between {} and {}".format(min_v, max_v))
else:
return val
return False
Now your calling loop can read:
while True:
val = input("...")
if val in valid_help_string_list:
# print help
else:
val = validate_input(val)
if val:
break
# use val
Note that this relies on the return from validate_input being either False or a number larger than 0; Python will interpret a zero return as False and not reach the break, so I recommend keeping min_v >= 0.

get the list and input from one function and run them in different function

i have a programm that generate the list and then i ask them to tell me what they want to do from the menu and this is where my problem start i was able to get the input form the user to different function but when i try to use the if else condition it doesn't check, below are my code
def menu(x,l):
print (x)
if x == 1:
return make_table(l)
if x == 2:
y= input("enter a row (as a number) or a column (as an uppercase letter")
if y in [ "1",'2','3']:
print("Minmum is:",minimum(y,l))
if x== 3:
print ('bye')
def main():
bad_filename = True
l =[]
while bad_filename == True:
try:
filename = input("Enter the filename: ")
fp = open(filename, "r")
for f_line in fp:
f_str=f_line.strip()
f_str=f_str.split(',')
for unit_str in f_str:
unit=float(unit_str)
l.append(unit)
bad_filename = False
except IOError:
print("Error: The file was not found: ", filename)
#print(l)
condition=True
while condition==True:
print('1- open\n','2- maximum')
x=input("Enter the choice")
menu(x,l)
main()
from the bottom function i can get list and i can get the user input and i can get the data and move it in second function but it wont work after that.thank you
I think your problem is simple, and has nothing to do with how you're passing values between functions.
In main, you're reading a value from the user like this:
x=input("Enter the choice")
The input function:
… reads a line from input, converts it to a string (stripping a trailing newline), and returns that.
So, if the user types 1 at the prompt, you get back the string "1".
Now, you pass that value—perfectly correctly—to menu.
In menu, you then try to compare it to various numbers, like this:
if x == 1:
But this will never be true. A string, like "1", is never equal to a number, like 1. They're not even the same kind of value, much less the same value.
So, you need to do one of two things:
Convert the input to an number. For example, change menu(x,l) to menu(int(x), l). OR…
Write menu to expect strings. For example, change if x == 1: to if x == "1":.
You may be wondering why that print (x) didn't help you debug the problem.
print(x) prints out the end-user-friendly string representation of whatever you give it. That is, it automatically calls the str function for you. For debugging purposes, you often want to use repr instead of str, to get the programmer-friendly string representation instead of the end-user-friendly string representation.
For example, print(str("10")) will print out 10—just like print(str(10)), so you can't tell them apart. But print(repr("10")) will print out '10', unlike print(repr(10)), while prints 10, so you can tell them apart. repr can also help you spot things like strings with invisible characters in them, having special "node" objects from a parser instead of just strings, etc.

Categories