how to use variables in Regex - python

I am trying to write a function that checks for a strong password. The password must contain one upper case, one lower case,a number and must be 8 characters long.
import re
def checker():
while True:
userInput = input(' Please input a password ')
passwordRegex = re.compile(r'[a-zA-Z0-9]+ {,8}')
match = passwordRegex.search(userInput)
if match:
print('Good!')
else:
print('Bad!')
checker()
This function always outputs Bad even when the password meets all the requirements. I have a feeling the error has to do with how I am using my Regex and Variables. I am using python 3.6.

Expanding on the answer from here:
passwordRegex = re.compile("^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])\S{8,}")
check out this demo
Using lookaheads we make sure there is at least one character from each group, then require at least 8 characters total. Note that you can customize the allowed characters (if you want to allow symbols) by changing the last group, the one before {8,}

Based on the feedback from #Aran-Fey and #Tomerikoo, i have updated my code and it works now.
import re
def checker():
while True:
userInput = input(' Please input a password ')
passwordRegex = re.search(r'^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$',userInput)
if passwordRegex:
break
print('Good!')
checker()

Related

Email Verification using re.search Python

Need help making email verifications with the variable 'pattern' and making it so that it loops if it doesn't contain whatever is within the pattern. Required to use re.search. I tried a couple of things for the last hour and this is where I'm kind of lost.
import re
pattern = '[a-zA-Z0-9]' + '[a-zA-Z0-9]'+'#[a-zA-Z]'+'(.com/.edu/.net)'
user_input = input('Enter Your Email:')
while user_input is not pattern:
if (re.search(pattern,user_input)):
print(re.seach(pattern,user_input))
print('Valid Email:'+ user_input)
else:
print(re.search(pattern,user_input))
print('Invalid Email:'+ user_input)
user_input = input('Enter Your Email:')```
The code is great, but the pattern lacks a bit of functionality. In fact for e-mail addresses, it misses the dash - and the underscore _. Luckily, you can just say to match \w. It is the same as if you would have specified [a-zA-Z0-9_]. (it still misses the dash though, so your approach is good but too short.) Anyway, there are a few further things that an address should meet.
it must start with a alphabetic character
While theoretically, the address could be composed of a single character at the start and only to after the # sign, and be almost infinitely long, it is highly unlikely
I suggest the pattern
'[a-zA-Z]+[a-zA-Z0-9_\-]{0,42}#[a-zA-Z]{2,42}\.((com)|(edu)|(net))\b?'
Limiting the number of characters with '{m,n}' lets you ensure that you won't have an overflow error when storing the address. Well and addresses shorter than 'a#bc.st' simply don't exist as at least two characters are required.
Lastly, the or-operator applies only to the immediate adjoin characters, so you need to group the mail extensions:
((com)|(edu)|(net))
import re
pattern = '[a-zA-Z]+[a-zA-Z0-9_\-]{0,42}#[a-zA-Z]{2,42}\.((com)|(edu)|(net))\b?'
while True:
user_input = input('Enter Your Email:')
if re.match(pattern, user_input):
print(re.search(pattern,user_input))
print('Valid Email:'+ user_input)
break
else:
print(re.match(pattern,user_input))
print('Invalid Email:'+ user_input)
I think, it is better if you use re.match() as it matches the string right from the start. Usually one doesn't like if you end up with 1abc#def.comm to be a valid address (because re.search() would find the valid string abc#def.com. With the same argumentation, you should add a \b to the end of the pattern
I made a slight modification to your pattern and to your code.
import re
pattern = '[a-zA-Z0-9]+#[a-zA-Z]+(\.com|\.edu|\.net)'
while True:
user_input = input('Enter Your Email:')
if (re.search(pattern,user_input)):
print(re.search(pattern,user_input))
print('Valid Email:'+ user_input)
break
else:
print(re.search(pattern,user_input))
print('Invalid Email:'+ user_input)
Here's an example run:
Enter Your Email:fred
None
Invalid Email:fred
Enter Your Email:mark#so.com
<re.Match object; span=(0, 11), match='mark#so.com'>
Valid Email:mark#so.com

how to make input in python non-punctuation sensitive

I'm trying to make a french practice chatbot however users may not type the punctuation in the code. how do I fix this? this is my code. for example, I want to make it so that no matter what you type, like instead of "bonjour!" they can type "bonjour" only with no punctuation sensitivity. this may be not possible without a module but I don't care if it requires a module
#menu starts first
line1 = ("=-----------=")
line2 = ("-------------")
bots = ["Adam", "Marie", "James", "Joy"]
def conversation():
print("For your conversation, Choose a Bot")
print(line1)
for bot in bots:
print(bot)
print(line2)
botopt = input("option: ")
if botopt==("Adam").lower():
print("adam: Bonjour!")
msg = input("Type a message: ")
if msg==("Bonjour! Comment ca va?").lower():
print("adam: Très bien. et toi?")
msg = input("Type a message: ")
if msg==("Tres bien. Comment tu t'appelle?").lower():
print("adam: Je m'appelle Adam. Et toi?")
input("Name: ")
print("adam: Enchante. ")
def menu():
print("Bonjour! Please choose an area to practice on.")
wordoption = ["Verbs"]
placeoption = ["Restaurant", "Store", "Conversation"]
#pour le optionnes
print("Vocabulary")
print("=----------=")
for wopt in wordoption:
print(wopt)
print("=---------=")
print("Locations")
print("-----------")
for popt in placeoption:
print(popt)
print("--------------")
opt = input("option: ")
if opt==("Conversation").lower():
conversation()
menu()
i cant find info online so i am not sure what to do, so please try to help me, send me modules if needed
I'm also new to python, so if my suggestion(s) do not seem adequate to you, then don't use them. I use Python v3.10.2, and tested my solution in IDLE shell v3.10.2.
In the header portion of your code, you typed:
line1 = ("=-----------=")
and line2 = ("-------------")
I believe these are global variables, because these appear outside a defined function. You used these effectively in conversation(), your first function:
print(line1)
for bot in bots:
print(bot)
print(line2)
But, you did not use these in menu(), the second function. Why not? If for no other reason, I suggest you use it in the second function as well for consistency. This should improve your programming style, and make it easier for others to understand your code.
For the punctuation problem, I think you can probably work this out without the need of an additional module. If I understand the problem correctly, you don't want users to enter punctuation of any kind (! , . : ; - " ') in response to your code. Is this right? If so, you want users to be confined to using letters A-Z or a-z and nothing else in their response.
You could create another function that takes a single argument, such as:
def Response(msg):
# create an empty string for processed word with punctuation removed
rsp = ''
#msg = "Bonjour!"
for c in range(len(msg)):
word = msg[c] # index of 1st character in msg string = 0, 2nd = 1, 3rd = 2, etc. . .
# add exceptions here
if word != '!': # exclamation mark
rsp = rsp + word
elif word != ',': # comma
rsp = rsp + word
elif word != '.': # period
rsp = rsp + word
# etc...
else:
print('Please, do not use punctuation of any kind.')
print (word)
Keep in mind that this will work for single words input from the user. For full sentences, you'll have to allow for spaces to be used for word spacing.
Also, the French comment in the menu() definition should read:
pour les options
I'll try my best to clearly answer your question.
The Problem
First, your code uses capitalization in such a way that the capitalization of the input has to match that of the strings you're checking it with.
To fix that, I recommend making all your input string AND the input-checking strings lowercase and unpunctuated.
To do that, you can either chose to manually adjust all your checking strings, or you can just use str.lower().
To allow the user to only input unpunctuated and lowercase text, you can make your own function customInput() that works like input() but also removes all punctuation, and also lowercases the text before return.
Normal code
Here is the code, feel free to use/modify:
# you NEED to import this for the unpunctuation to work
from string import punctuation
# this is a function that works like input(), but removes all punctuation and makes the input lowercase
def customInput(text:str):
inputText = input(text).lower()
for character in [symbol for symbol in punctuation]:
inputText = inputText.replace(character,'')
return inputText
# do remember to use string.lower() on the strings you check the input with
Code for also removing numbers
If you want to remove numbers too from the input, then you can use this code:
# you NEED to import these for the unpunctuation to work
from string import punctuation, digits
# this is a function that works like input(), but removes all punctuation and numbers, and makes the input lowercase
def customInput(text:str):
inputText = input(text).lower()
for character in [symbol for symbol in punctuation] + [number for number in digits]:
inputText = inputText.replace(character,'')
return inputText
# do remember to use string.lower() on the strings you check the input with
Example usage
# an example of using customInput()
example = customInput('Saisissez une réponse: ')
# printing answer out
print(example)
# There will be no punctuation/capitalization in the printed output
Hope this helps! If it doesn't, comment and I will update the answer.

Are all these IF's and None's the best way to handle RE?

I have been trying to make my own, very simple program to check if the text string the user has copied can be considered a strong password, based on the regular exressions. In the program, I wanted a strong password to be considered to have at least 8 characters, at least one lower and one upper case character, and also at least one digit.
The code I wrote looks like this:
import re, pyperclip
# regex for password
regexEight = re.compile(r"\w{8,100}") # regex for 8 char.
regexLower = re.compile(r'[a-z]') # regex for lower.
regexUpper = re.compile(r"[A-Z]") # regex for upper.
regexNum = re.compile(r"\d") # regex for number.
# get text from paste
text = str(pyperclip.paste())
# see if text matches every regex.
mo = regexEight.search(text)
if mo != None:
exit
else:
print("Password to short.")
mo2 = regexLower.search(text)
if mo2 != None:
exit
else:
print("Password need to contain at least one lower case character.")
mo3 = regexUpper.search(text)
if mo3 != None:
exit
else:
print("Password need to contain at least on upper case character.")
mo4 = regexNum.search(text)
if mo4 != None:
exit
else:
print("Password need to contain at least one digit.")
# return this if every regex matches.
if mo or mo2 or mo3 or mo4 != None:
print("You have a strong password.")
I'm a complete beginner at RE so I used None to see if the object was matching or not (if it matched it returned the particular password, if it didn't mo(1,2,3) = None). However, I kind of feel that this way is quite unusual, or at least I don't think that is how RE should be handled, so that is why I asked here.
Is there any way to make this code simpler? Or is this way quite OK for a program? In my opinion it feels like the code would be better without all the if's and the None's. Is there a way to get rid of them?
I think a decent general approach would be to create some structure which holds the regexes that you want to check and the corresponding error messages.
import re
tests = [
(re.compile(r"\w{8,100}"), "Too short."),
(re.compile(r"[a-z]"), "Add lowercase letter."),
(re.compile(r"[A-Z]"), "Add uppercase letter."),
(re.compile(r"\d"), "Add number.")
]
check = True
for regex, message in tests:
if regex.search("example_password") is None:
print(message)
check = False
if check:
print("Strong password.")
You're making this way more complex than it needs to be:
def validate_password(password):
if not password or len(password) < 8:
print("Password too short!")
elif password == password.lower() or password == password.upper():
print("Password must contain at least one lowercase and one uppercase character!")
elif not any(c.isdigit() for c in password):
print("Password must contain at least one digit!")
else:
return True # all is well
return False # didn't validate

check user_input with if token in a loop

I am trying to write a function that checks my input to see whether I have entered the character '?'.
This is what I got so far:
def check_word():
word = []
check = 0
user_input = input('Please enter a word that does not contain ?: ')
for token in user_input.split():
if token == '?':
print('Error')
check_word()
My input: hello?
It is supposed to show 'Error'. But it doesn't show anything. Could you please tell me what wrong it is in my code.
I would use the in operator to do this
def check_word(s):
if '?' in s:
print('Error')
For example
>>> check_word('foobar')
>>> check_word('foo?')
Error
The problem is how you split the string of the user_input.
user_input.split():
The example doesn't contain whitespaces so the condition isn't met. If you want for example to check a sentence with spaces, you should split it like this: user_input.split(' ') to split it on the spaces.
But for this example you have two choices:
1) You can just iterate over the input itself because you want to check every char in the string for whether it's a ?.
That is, change user_input.split(): into simply user_input without splitting. This option is good if you might ever want to add some sort of action for each char.
2) It's very easy just to use in, like this:
if '?' in s:
print('There is a question mark in the string')
This is a very simple solution that you can expand and check for other chars in the string as well.
It's because user_input.split() splits the user_input by whitespace. Since hello? does not contain any whitespaces, token is equal to your input and the loop is executed once.
You should iterate over user_input instead, or simply check if '?' in user_input.

Changing inputs into titles, issue with handling raw spaces

so I'm quite new to programming and I'm trying to learn python as a starter.
I'm trying to make a function that does multiple things (I'm going to use it for limiting inputs on names).
Rejects purely numerical inputs
Rejects inputs made purely of spaces
Rejects null inputs
Changes the input into a title
def debugstr(inputa):
inputa = inputa.replace(" ", "")
try:
int(inputa)
inputb = debugstr(input("Invalid input, please enter Alphabetic strings only: "))
except:
if inputa == "":
debugstr(input("Invalid input, please enter Alphabetic strings only: "))
else:
return inputa.title()
The issue that I have is that the code will only reject blank inputs on the first try when running the function, if something is rejected once and the user inputs a series of spaces again, then it will just accept it as an input.
Thanks for your time in advance! It's very appreciated :D
A more natural way of handling this (without calling the same function from within itself) is:
def make_title():
def get_user_input():
return input('Enter an alphabetic string: ')
while True:
s = get_user_input()
s = s.strip()
if not s:
print('blank input!')
continue
if s.isdigit():
print('contains only digits!')
continue
return s.title()
print(make_title())
Some notes:
Try not to repeat yourself (e.g. the duplicated error message in your code)
Python contains many useful string methods and s.isdigit() returns True if s contains only numbers
You can strip the whitespace from your input with s.strip() and if you're left with the empty string, '', if not s will be True (the empty string is equivalent to False.
In python 3, you can use isinstance to check if an object is a string.
word = input("Enter string: ")
def checkString(s):
if isinstance(s, str):
print('is a string')
elif not s:
print('empty')
else:
print('not a string')

Categories