I am trying to create a function that accesses if a user entered username matches a regular expression. Here is my code:
def regular_expression():
rules = "[A-Z]^{1}[a-zA-Z0-9]+[0-9]$"
while True:
username = str(input("Username Must have:\n"
"- First character must be an upper case letter\n"
" - Middle can be any letter or number\n"
"- Last character must be a number\n"
"> "
))
if re.fullmatch(rules, username):
print("Accepted")
This is the error I receive:
return _compile(pattern, flags).fullmatch(string)
p = sre_compile.compile(pattern, flags)
p = sre_parse.parse(p, flags)
p = _parse_sub(source, pattern, flags & SRE_FLAG_VERBOSE, 0)
source.tell() - here + len(this))
re.error: multiple repeat at position 9
The problem is ^{1} that inside your rules variable, what the purpose of it?
I managed to make this work with this:
def regular_expression():
rules = "[A-Z][a-zA-Z0-9]+[0-9]$"
while True:
username = str(input("Username Must have:\n"
"- First character must be an upper case letter\n"
" - Middle can be any letter or number\n"
"- Last character must be a number\n"
"> "
))
if re.fullmatch(rules, username):
print("Accepted")
else:
print("Invalid username")
Related
For the get_letter_from_user function, while using the while loop for validation, it keeps repeating the invalid input; I want to make sure that it is a single letter and lower case, and I want to make sure that it doesn't equal the second parameter of the function. I'm not sure what I'm doing wrong, though. (and how to get gud at coding if u have tips)
def get_text_from_user(prompt):
return input(prompt).lower()
def get_letter_from_user(prompt, not_allowed):
not_allowed = ''
allowed = input(prompt).lower()
while not allowed == not_allowed or allowed.isalpha() or len(allowed) > 1:
allowed = str(input('Invalid letter, try again:'))
return allowed
def main():
text = get_text_from_user("Enter some text: ")
ltr1 = get_letter_from_user("Enter a letter: ", '')
ltr2 = get_letter_from_user("Enter another letter: ", ltr1)
new_text = text.replace(ltr1,ltr2)
print("The new text is", new_text)
if __name__ == "__main__":
main()
Suggestion for the function:
def get_letter_from_user(prompt, not_allowed):
allowed = input(prompt).lower()
while allowed == not_allowed or len(allowed) > 1:
print('not_allowed:',not_allowed)
allowed = str(input('Invalid letter, try again:'))
return allowed
ltr1 = get_letter_from_user("Enter a letter: ", '')
ltr2 = get_letter_from_user("Enter another letter: ", ltr1)
Sample output:
Enter a letter: d
Enter another letter: d
not_allowed: d
Invalid letter, try again:d
not_allowed: d
Invalid letter, try again:a
To replace a letter or sequence of letters in a string, you might want to take a look at the string.replace() function:
text = input('Enter some text: ')
find = input('Enter a letter to replace: ')
replace_with = input(f'Enter a letter to replace \'{find}\' with: ')
replaced = text.replace(find, reolace_with)
print('The new text is:', replaced)
To add another little detail because you asked how to get better at coding:
I would never make a function with a parameter that is immediately changed to an empty string. Like:
def get_letter_from_user(prompt, not_allowed):
not_allowed = ''
Rather use a default value like this:
def get_letter_from_user(prompt, not_allowed=''):
...
I am coding a password analyzer with several properties, one being that the user's password must not have special characters (##$%^&*) except for ! (exclamation mark) and _ (underscore). I am using the .isalnum() method for this purpose but I cannot figure out a way to make it so it doesn't return True when ! or _ is used WITH any other special character (ex: Python$ returns False but Python_ returns True).
Here is my code:
password = input('Enter a password: ')
if not password.isalnum():
if '_' in password or '!' in password:
pass
else:
print('Your password must not include any special characters or symbols!')
The most intuitive way is to check every character.
if not all(c.isalnum() or c in '_!' for c in password):
print('Your password must not include any special characters or symbols!')
This is one way. replace the ! and _ withe empty string and then check with isalnum().
password = input('Enter a password: ')
pwd = password.replace('_', '').replace('!', '')
if pwd.isalnum() and ('_' in password or '!' in password):
pass
else:
print('Your password must not include any special characters or symbols!')
Another way of checking it is by using regex
import re
x = input('Enter a password: ')
t = re.fullmatch('[A-Za-z0-9_!]+', x)
if not t:
print('Your password must not include any special characters or symbols!')
def is_pass_ok(password):
if password.replace('_', '').replace('!','').isalnum():
return True
return False
password = input('Enter a password: ')
if not is_pass_ok(password):
print('Your password must not include any special characters or symbols!')
By removing all allowed special characters, i.e. _ and !:
password.replace('_', '').replace('!','')
it remains only to check for alphanumeric characters (.isalnum()).
I'm not sure how to make this code print a message if it finds the user types a special character and/or number and exits the code instead of just printing out the special character and/or number again.
I'm quite new to here, any help would be appreciated. My code is below:
#!/bin/python3
alphabet = 'abcdefghijklmnopqrstuvwxyz'
special = '[#_!#$%^&*()<>?/\|}{~:]1234567890'
newMessage = ''
message = input('Please enter a message to encyrpt: ').lower()
key = input('Please enter a key from 1-26: ')
key = int(key)
for character in message:
if character in alphabet:
position = alphabet.find(character)
newPosition = (position + key) % 26
newCharacter = alphabet[newPosition]
#print('The new character is is:', newCharacter)
newMessage += newCharacter
else:
newMessage += character
print('Your new encrypted message is:', newMessage)
The below example:
Checks each character of the string message given by the user at runtime and passes it into a list specialInMessage = [c for c in special if c in message]
Checks the list (if specialInMessage:), printing a message to the console and exiting the execution of any further code using the builtin sys module (sys.exit()) if there are any characters that made it through the above list comprehension into specialInMessage
If the above conditional (if specialInMessage) does not pass - i.e. there are no values from special present in message - the code will not execute the block exiting the program and continue to ask for a key value, encrypt message etc.
import sys # Import builtin sys module
alphabet = 'abcdefghijklmnopqrstuvwxyz'
special = '[#_!#$%^&*()<>?/\|}{~:]1234567890'
newMessage = ''
message = input('Please enter a message to encyrpt: ').lower()
specialInMessage = [c for c in special if c in message] # Make a list of characters from special that are present in message
if specialInMessage: # If new list has any characters in it
print('Invalid character found in message, exiting program') # Message to console
sys.exit() # End execution of code
key = input('Please enter a key from 1-26: ')
key = int(key)
for character in message:
if character in alphabet:
position = alphabet.find(character)
newPosition = (position + key) % 26
newCharacter = alphabet[newPosition]
newMessage += newCharacter
else:
newMessage += character
print(f'Your new encrypted message is: {newMessage}')
If you want to tell the user specifically which character(s) from their input are invalid these can be accessed directly from the specialInMessage list - probably best from within the if specialInMessage block to ensure that list index access is only attempted when there are actually invalid characters at runtime.
you can simply use break
alphabet = 'abcdefghijklmnopqrstuvwxyz'
special = '[#_!#$%^&*()<>?/\|}{~:]1234567890'
newMessage = ''
message = input('Please enter a message to encyrpt: ').lower()
key = input('Please enter a key from 1-26: ')
key = int(key)
for character in message:
if character in alphabet:
position = alphabet.find(character)
newPosition = (position + key) % 26
newCharacter = alphabet[newPosition]
#print('The new character is is:', newCharacter)
newMessage += newCharacter
elif character in special:
newMessage = 'encrypting Error'
break
else:
newMessage += character
print('Your new encrypted message is:', newMessage)
I'm trying to make a program where I input a name and a surname and the code checks if the name is invalid (list of invalidiations below). If it has any invalidations, it asks me to say the name again and presents me a list of all the invalidations.
Invalidations list (I'll show the code version too):
- The name has digits
- The name has symbols
- The name has no spaces
- It has more then one space
- One of the names is either too short or too long
- The first letter of the name is a space
- The last letter of the name is a space
I can't use exceptions here, because these are not code erros. I've made it with Ifs, but it got to a point where there a simply lots of Ifs for it to be viable.
def has_digits(name):
digits = any(c.isdigit() for c in name)
if digits == True:
return True
print("Your name has digits.")
else:
return False
def has_symbols(name):
symbols = any(not c.isalnum() and not c.isspace() for c in name)
if symbols == True:
return True
print("Your name has symbols.")
else:
return False
def has_no_spaces(name):
spaces = any(c.isspace() for c in name)
if not spaces == True:
return True
print("You only gave me a name.")
else:
return False
def many_spaces(name):
m_s = name.count(' ') > 1
if m_s == True:
return True
print("Your name has more than one space.")
else:
return False
def unrealistic_length(name, surname):
length= (float(len(name)) < 3 or float(len(name)) > 12) or float(len(surname)) < 5 or float(len(surname) > 15)
if length == True:
return True
print("Your name has an unrealistic size.")
else:
return False
def first_space(name):
f_s = name[0] == " "
if f_s == True:
return True
print("The first letter of your name is a space.")
else:
return False
def last_space(name):
l_s = name[-1] == " "
if l_s == True:
return True
print("The last letter of your name is a space.")
else:
return False
name = "bruh browski"
namesplit = name.split(" ")
name1 = namesplit[0]
name2 = namesplit[1]
print(has_digits(name))
print(has_symbols(name))
print(has_no_spaces(name))
print(many_spaces(name))
print(unrealistic_length(name1, name2))
print(first_space(name))
print(last_space(name))
Maybe the prints shouldn't be in the defs themselves. I don't know. I'm almost sure doing a for loop is the way to go, but I just can't imagine how to do it.
Result:
False
False
False
False
False
False
False
The methods you've used to define exactly what counts as each "invalidation" will have to stay, unless you can replace them with something else that does the same thing. But you can check all of those conditions at once using a generator expression:
if any(is_invalid(name) for is_invalid in [
has_digits, has_symbols, has_no_spaces, many_spaces, unrealistic_length, first_name, last_name
]):
# then this string is invalid
# otherwise, all of those returned false, meaning the string is valid.
You can then use that condition to determine when to stop asking the user, or however else you need to.
If you wanted to not individually define all those functions, you could also maybe use lambdas to do the same thing.
As a sidenote, before actually using this in production for checking the validity of names, I advise having a look at the list of Falsehoods Programmers Believe about Names. It's a fun read even if it's not relevant to your use case, though.
You could have a single function which calls all of your other functions and handles it appropriately.
def master_verify(name):
# Put all your verify functions in the list below.
verify_funcs = [has_digits, has_symbols, has_no_spaces, many_spaces,
unrealistic_length, first_space, last_space]
# It will return True if any your functions return True. In this case,
# returning True means the name is invalid (matching your other
# function design). Returning False means the name is valid.
return any(is_invalid(name) for is_invalid in verify_funcs)
Since you mentioned you want the program to find any name errors and ask the user to try again, we can write a loop to handle this.
def get_name():
while True:
# Loop until you get a good name
name = input("Enter your name: ").strip()
if master_verify(name):
# Remember, if True this means invalid
print("Invalid name. Try again.")
continue # continue jumps to the top of a loop, skipping everything else.
return name # Will only get here if the name is valid.
I also suggest you should do the name and surname split inside your unrealistic_length function.
Then, all you need to do is
name = get_name()
# All of the validation has already happened.
print(f"The correct and validated name is: {name}")
Last but not least, anything in a function after a return is unreachable. So a lot of your prints will never happen. Put the print statements before your return.
Alright. I've managed to do it by myself. I still fill there's a better way to do it, but this is the way I found.
errors_list = []
print("Hi. Tell me your first and last name.")
def choose_name(name):
global fname
global sname
fname = ""
sname = ""
global errors_list
try:
no_letters = any(c.isalpha() for c in name)
no_spaces = name.count(" ") == 0
digits = any(c.isdigit() for c in name)
symbols = any(not c.isalnum() and not c.isspace() for c in name)
many_spaces = name.count(" ") > 1
first_space = name[0] == " "
last_space = name[-1] == " "
if no_letters == False:
errors_list.append("It has no letters")
if no_spaces == True:
errors_list.append("It has no spaces")
else:
namesplit = name.split(" ")
fname = namesplit[0]
sname = namesplit[1]
pass
if fname and sname is not "":
bad_length = (float(len(fname)) < 3 or float(len(fname)) > 12) or float(len(sname)) < 4 or float(len(sname) > 15)
if bad_length == True:
errors_list.append("One of your names has an unrealistic size")
pass
else:
bad_length = (float(len(name)) < 3 or float(len(name)) > 12)
if bad_length == True:
errors_list.append("It has an unrealistic size")
pass
if digits == True:
errors_list.append("It has digits")
pass
if symbols == True:
errors_list.append("It has symbols")
pass
if many_spaces == True:
errors_list.append("It has more than one space")
pass
if first_space == True:
errors_list.append("The first letter is a space")
pass
if last_space == True:
errors_list.append("The last letter is a space")
pass
except IndexError:
print("You must write something. Try again.")
name = input("My name is ").title()
choose_name(name)
name = input("My name is ").title()
choose_name(name)
while True:
if len(errors_list) != 0:
print("Your name has these errors:")
for i in errors_list:
print(" " + str(errors_list.index(i) + 1) + "- " + i + ".")
print("Try again.")
errors_list.clear()
name = input("My name is ").title()
choose_name(name)
else:
print("Nice to meet you, " + fname + " " + sname + ".")
break
Result when I type the name '----... '
Hi. Tell me your first and last name.
My name is ----...
Your name has these errors:
1- It has no letters.
2- It has symbols.
3- It has more than one space.
4- The last letter is a space.
Try again.
My name is
I am trying to return the password entered by a user if it matches a-z,A-Z,0-9,_,- otherwise a ValueError will be executed within a try clause. Here is my line of code that doesn't seem to be working as it allows just about anything like (?.,##$%^*)
return re.match('^[A-Za-z0-9_-]*$',password)
With the Kleene closure, you allow an empty string as a correct password. You can use the + special character to match one repetitions of the valid characters:
def validate(password):
match = re.match('^[a-z0-9_-]+$', password, re.I)
if match is not None:
return password
else:
raise ValueError
Outline
Using sets and set-subtraction is likely a simpler solution.
Code
from string import ascii_letters, digits
PASSWORD_SET = set(ascii_letters + digits + "_-")
def has_only_password_letters(candidate):
return not(set(candidate) - PASSWORD_SET)
or:
def has_only_password_letters(candidate):
return all(c in PASSWORD_SET for c in candidate)
Tests
>>> def test_password(password):
... if has_only_password_letters(password):
... print "Okay: ", password
... else:
... print "Nuh-uh: ", password
...
>>> test_password("asdasd123123")
Okay: asdasd123123
>>> test_password("asdasd123123!!!")
Nuh-uh: asdasd123123!!!
Here is a non-regex solution using isalnum:
for c in password:
if not (c.isalnum() or c in ['_', '-']):
raise ValueError('Invalid character in password')