Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Python Regular Expressions in Python Introduction to Regular Expressions Compiling and Loops

igsm '
igsm '
10,440 Points

Boolean with re?

Hey. Can you help please with the following. Using RE, I want to check a string, which is meant to be a passwords. True if it contains >= 10 chars, at least one lower letter, one capital letter and one number; else False. How would a code look like. Thanks.

e.g. two cases:

True = 'bAse730onE4'

False = 'saaaa90'

re.match('[a-zA-Z0-9]+', password)

3 Answers

Chris Freeman
MOD
Chris Freeman
Treehouse Moderator 68,441 Points

Because you are looking for the AND of multiple conditions there isn't a short single concise regexp that will solve your needs because your conditions are not order dependent. That is, you would have to check for all combinations of a condition followed by all others. For example lowercase followed by uppercase followed by number and being 10 characters long, plus the other 5 combinations, ORed together in a single regexp.

The other option is to create the 3 search patterns and check that they each match plush a length check.

patterns = []
patterns.append(re.compile(r'[a-z]+')) #lowercase
patterns.append(re.compile(r'[A-Z]+')) #uppercase
patterns.append(re.compile(r'[0-9]+') )# number
password_good = True
if len(password_string) < 10:
    password_good = False
else:
    for pat in patterns:
        if not pat.search(password_string):
            # pattern not found
            password_good = False
            break

You could include the length check as a regexp:

patterns.append(re.compile(r'\w{10,}'))

I'll work on the combined uber-regexp to show it's complications and ammend my answer.

EDIT: Here is a single regexp pattern to match against. Yeah, it's not pretty:

In [101]: patx = re.compile(r'''
\w*[a-z]+\w*[A-Z]+\w*[0-9]+\w*|
\w*[a-z]+\w*[0-9]+\w*[A-Z]+\w*|
\w*[A-Z]+\w*[a-z]+\w*[0-9]+\w*|
\w*[A-Z]+\w*[0-9]+\w*[a-z]+\w*|
\w*[0-9]+\w*[a-z]+\w*[A-Z]+\w*|
\w*[0-9]+\w*[A-Z]+\w*[a-z]+\w* 
''', re.X)

In [102]: patx.search("")

In [103]: patx.search("a")

In [104]: patx.search("aA1")
Out[104]: <_sre.SRE_Match object; span=(0, 3), match='aA1'>

Now you can use:

if not len(password) > 10 and patx.search(password)
    print("Bad Password")
Chris Freeman
Chris Freeman
Treehouse Moderator 68,441 Points

Added uber-regexp to answer.

If switching to re.match instead of search, use the patx as above:

re.match(patx, password)

If you choose to switch to re.search, you can remove the leading and trailing \w* from each line in the patx regexp.

This works, too:

import re


def check_password(string):
    return (re.search('[a-z]+', string) and re.search('[A-Z]+', string) 
            and re.search('[0-9]+', string) and len(string) > 9)

Technically, it actually returns None when the password is bad, but that's fine in a lot of applications. Easy modification if the False return is important:

import re


def check_password(string):
    if (re.search('[a-z]+', string) and re.search('[A-Z]+', string) 
            and re.search('[0-9]+', string) and len(string) > 9):
        return True
    else:
        return False

Hi Igor, re.search and re.match return match objects. If the item isn't found, it returns None (the special value). re.match checks for a match at the beginning of the string, whereas re.search checks anywhere in the string. You can use the boolean operator "and" to check multiple conditions--for example:

def check_two(string):
   return re.search(\w+) and re.search(\d+)

returns True if the string contains at least one word character ([a-zA-Z0-9_]) and at least one decimal digit. You can get more specific by using a set definition, like [a-z]+.

igsm '
igsm '
10,440 Points

Thank you. Really helpful!