1

I have the following code and while it works for just checking one function (say the lower case), it stops working when two conditions are introduced. Could someone shed some light for teaching purposes, on why this is the case, give a solution, and explain the rationale. Note: this is not a duplicate of any other question, as the other examples don't explicitly deal with string boolean commands.

Expected outcome: The email address should only be generated IF the username input is lowercase AND contains digits. (e.g. username123 is acceptable, USER is not, USER123 is not)

The solution/answer must be simple and ideally not include a rewrite of the code (i.e without rewriting the function and introducing parameters etc, if this as possible)

Code:

def main():
   print("*************************** Create an e-mail address*********************")
   print("***************************                                               ********************** ")

   username=input("Please enter your desired username:" )

   if username.islower() and username.isdigit():
         email=username+"@gmail.com"
         print("Your unique email address is now:", email)
   else:
         print("Your username needs to be lower case ...............")
         main()

main()

As mentioned, the below code (checking for just the islower) works ....

   if username.islower():
         email=username+"@gmail.com"
         print("Your unique email address is now:", email)
   else:
         print("Your username needs to be lower case ...............")
         main()

Working output:

*************************** Create an e-mail address*********************
***************************                                               ********************** 
Please enter your desired username:USER
Your username needs to be lower case ...............
*************************** Create an e-mail address*********************
***************************                                               ********************** 
Please enter your desired username:user
Your unique email address is now: user@gmail.com
>>> 

UPDATE: Someone suggested it was due to the missing (), but this isn't the case:

def main():
   print("*************************** Create an e-mail address*********************")
   print("***************************                                               ********************** ")

   username=input("Please enter your desired username:" )
   if username.islower() and username.isdigit():
         email=username+"@gmail.com"
         print("Your unique email address is now:", email)
   else:
         print("Your username needs to be lower case ...............")
         main()
main()

Erroneous output:

*************************** Create an e-mail address*********************
***************************                                               ********************** 
Please enter your desired username:USER
Your username needs to be lower case ...............
*************************** Create an e-mail address*********************
***************************                                               ********************** 
Please enter your desired username:user
Your username needs to be lower case ...............
*************************** Create an e-mail address*********************
***************************                                               ********************** 
Please enter your desired username:user123
Your username needs to be lower case ...............
*************************** Create an e-mail address*********************
***************************                                               ********************** 
Please enter your desired username:

Removing the recursive main() call doesn't change things either:

def main():
   print("*************************** Create an e-mail address*********************")
   print("***************************                                               ********************** ")
   username=input("Please enter your desired username:" )
   if username.islower() and username.isdigit():
         email=username+"@gmail.com"
         print("Your unique email address is now:", email)
   else:
         print("Your username needs to be lower case and contain digits...............")
main()

Erroneous output:

Please enter your desired username:USERNAME
Your username needs to be lower case and contain digits...............
>>> main()
*************************** Create an e-mail address*********************
***************************                                               ********************** 
Please enter your desired username:username123
Your username needs to be lower case and contain digits...............
>>> 

Using OR instead of AND does not work either

Output below, when changed to OR

Please enter your desired username:USERNAME
Your username needs to be lower case and contain digits...............
>>> main()
*************************** Create an e-mail address*********************
***************************                                               ********************** 
Please enter your desired username:username
Your unique email address is now: username@gmail.com
>>> 

Trying another suggested answer below using set(range(10)).intersection:

The following - still not working:

def main():
   print("*************************** Create an e-mail address*********************")
   print("***************************                                               ********************** ")
   username=input("Please enter your desired username:" )
   #if username.islower() or username.isdigit():
   if username.islower() and set(range(10)).intersection(username):
         email=username+"@gmail.com"
         print("Your unique email address is now:", email)
   else:
         print("Your username needs to be lower case and contain digits...............")
main()

Output

  >>> main()
    *************************** Create an e-mail address*********************
    ***************************                                               ********************** 
    Please enter your desired username:user
    Your username needs to be lower case and contain digits...............
    >>> main()
    *************************** Create an e-mail address*********************
    ***************************                                               ********************** 
    Please enter your desired username:username123
    Your username needs to be lower case and contain digits...............
    >>> 
  • 7
    you forgot the parentheses for the islower() function call in the first example. – Zinki Jun 27 '17 at 09:10
  • Sorry, I've added that in the code. That is in the original code - and does not work. Do run it and see -! –  Jun 27 '17 at 09:13
  • Your first code snippet is recursive; you call `main()` in `main()` – Chris_Rands Jun 27 '17 at 09:14
  • Chris, yes, but removing that doesn't solve the problem (see update) –  Jun 27 '17 at 09:17
  • 'and username.isdigit()' ... 'user' is false for this. did you mean 'and not username.isdigit()' and requires both sides to evaluate to True – PythonTester Jun 27 '17 at 09:18
  • @pythoncarrot you are checking `islower() and isdigit()`. Digits are not lowercase and letters are not digits, so its always false. I assume you either mean `or` (name is lower case or purely numbers) or `and not` (lowercase and not purely numbers) or something similar. – Zinki Jun 27 '17 at 09:19
  • I want the username to be validated: the user should only input a lowercase entry WITH numbers. so the email should only be generated IF the username is BOTH lowercase AND has digits ...? –  Jun 27 '17 at 09:20
  • @pythoncarrot then you don't want "isdigits()", but you want some function that checks if the username CONTAINS digits, which you may have to write yourself. – Zinki Jun 27 '17 at 09:21
  • @pythoncarrot please update question to contain valid and invalid names, it makes the answering alot simpler. – PythonTester Jun 27 '17 at 09:23
  • see update - has been done. valid: username123 invalid: USERNAME invalid: username. And I wish someone would upvote my q rather than whoever downvoted it (why?!) ....makes life hard for a newbie like me to build up a reputation! –  Jun 27 '17 at 09:24
  • Is username *a1b2c3* valid? Or should both letter and digit sets be consequent, such as in your examples? – E.Z Jun 27 '17 at 10:12
  • Nevermind, I have added a possible solution for both cases... – E.Z Jun 27 '17 at 11:39

3 Answers3

1

You can create a simple function

def hasNumbers(inputString):
      return any(char.isdigit() for char in inputString)
.
.
.
if username.islower() and hasNumbers(username):
.
.
.

and then use it in the if statement. This is the source I found it from: check if a string contains a number . You can also use regex if you prefer that, using the re module. But for something as small as this, I would recommend you go with a separate function. Its a more...simpler solution.

Regex version:

import re

def main():
   print("*************************** Create an e-mail address*********************")
   print("***************************                                               ********************** ")

   username=str(input("Please enter your desired username:" ))

   pat = re.compile(r'\d')

   if username.islower() and re.search(pat, username):
         email=username+"@gmail.com"
         print("Your unique email address is now:", email)
   else:
         print("Your username needs to be lower case ...............")
         main()

main()
hridayns
  • 697
  • 8
  • 16
  • changing it to "or" instead of "and" does not work either. See edit with output –  Jun 27 '17 at 09:19
  • depends if the OP is intending to allow numeric usernames: if not intending numbers as username then the 2nd part requires a not operator. – PythonTester Jun 27 '17 at 09:20
  • I agree. I am trying to find out what he really wants as output. – hridayns Jun 27 '17 at 09:21
  • Oh I get it now. He wants the username to contain lowercase alphabets and digits – hridayns Jun 27 '17 at 09:22
  • From this link: https://stackoverflow.com/questions/19859282/check-if-a-string-contains-a-number Use the function `def hasNumbers(inputString): return any(char.isdigit() for char in inputString)` and use the function passing your string as the argument. Then all you need to do is, change the error message. Sorry, *she – hridayns Jun 27 '17 at 09:26
  • isdigit() is not the right function to use for a string. it works only on a character. – hridayns Jun 27 '17 at 09:26
  • @pythoncarrot I think I have got it. Shall i edit the answer? – hridayns Jun 27 '17 at 09:28
  • surely there is a way then to see if a STRING contains a list of digits (0 to 9) and include it simply in the if statement above? Is reg ex the only way to go.... –  Jun 27 '17 at 09:28
  • Regex is quite easy using the re module. I don't think you can simplify it more than that. :) – hridayns Jun 27 '17 at 09:30
  • Are you able to add an answer using regex within the if –  Jun 27 '17 at 09:38
  • @pythoncarrot Please do tick this as answer if it worked out :) So that it helps the others in the SO community as well. Thanks. – hridayns Jun 27 '17 at 10:01
1

The issue with this line

if username.islower() and username.isdigit()

is that isdigit() returns True only if the entire string is numbers and islower() will obviously only return True if the entire string is lower case characters. This means that this statement will always fail as both conditions cannot be true.

If we rethink the logic a bit what we need to test is that the email only contains alphanumeric characters (numbers and letters) but does not contain any upper case letters. This gives us:

if username.isalnum() and (not any(c.isupper() for c in username)

Aran K
  • 289
  • 2
  • 8
1

It has been stated that the problem with your code is if you execute username.isdigit() it returns False statement because the variable username is not completely filled with digits, though, islower() is not as strict:

username = input(' -->> ')
-->> abc123

username.isdigit()

False

username.islower()

True

In your specific case, you may omit warnings if there are uppercase letters as you may transform them into lowercase. If you need a solution where there is also a check for uppercase letters, then you should also read the additional section in the end.

If the structure of username does not really bother you, i.e. you simply want it to contain both lowercase letters and digits, then you may simply check if they both exist using regex:

import re  # regular expressions

username = 'Abc123'  # similar to input() as it also returns 'str' class

if re.match('^[a-z0-9]*$', username.lower()):  # username.lower() makes letters lowercase. You could assign it to a new variable if needed.
    email = username.lower() + '@gmail.com'
    print('Your e-mail address is: {}'.format(email))

It works well even if username = 'A1b2C3', for instance.


However, if the structure is important and you want digits follow letters at any cost, you should divide the username into two subsets, one containing letters and other containing digits and check if both exist in the correct order. Note that it is just a personal approach:

  • Firstly, we check username if we can successively divide it into two sets of letters and digits, not more and not less;

  • Secondly, we check if the first subset contains letters and the second subset contains digits;

  • If the conditions are satisfied, then we create an e-mail.

The code should be the following:

import re

print('Example of username: george1337')
username = 'Abc123'; username = username.lower()

if len(re.findall('\d+|\D+', username)) == 2:
    subset_1, subset_2 = [subset for subset in re.findall('\d+|\D+', username)]
else:
    print('Not valid username: see example')

if subset_1.islower() and subset_2.isdigit():
    email = username + '@gmail.com'
    print('Your e-mail address is: {}'.format(email))
else:
    print('Digits must follow letters, not vice versa')

Your e-mail address is: abc123@gmail.com

username = 'a2BB3dd4'; username = username.lower()

if len(re.findall('\d+|\D+', username)) == 2:
    subset_1, subset_2 = [subset for subset in re.findall('\d+|\D+', username)]
else:
    print('Not valid username: see example')

Not valid username: see example


Additional section

Okay. If you wish to raise a warning if there are uppercase letters, then you should not execute username = username.lower(). The 'uppercase condition' will be automatically checked in the second section as there is if subset_1.islower(). You should then simply add another print indicating that uppercase letters are not allowed. The same goes with the first section.

I hope that helps!

E.Z
  • 1,958
  • 1
  • 18
  • 27