1

The only special char position that will match is the end of a password. If the special char is at the beginning, or anywhere other than the end, it will fail to match and reject the password.

import re

while True:
    password = input("Please enter a password containing at least 6 letters, \n "
                "one number, one capital letter, and at least one special character. ")

    pattern = r"[A-Z]+?[A-Za-z]{6,}?[0-9]+?[^a-zA-Z0-9]+?"

    if not re.search(pattern, password):
        print("Please try again")

    else:
        print("Your new password is: ", password)
        break

I would like to accept passwords that contain special chars and numbers anywhere in them, not just at the end, e.g.

  • @#$Chuckles23
  • Chuck#$les23
  • 23Chuckles@#$

I've tried using regex code suggested in other answers, but so far none of them work for my scenario.

Troy
  • 101
  • 9
  • See the solution above or this for a regex solution: https://stackoverflow.com/questions/5142103/regex-to-validate-password-strength – Ogre Codes Jun 22 '19 at 01:33

2 Answers2

3

Try using lookaheads in your password regex pattern:

pattern = r'^(?=.*[0-9])(?=.*[A-Z])(?=.*[^a-zA-Z0-9]).{6,}$'
if not re.search(pattern, password):
    print("Please try again")

Here is a brief explanation of the regex pattern:

^                        from the start of the password
    (?=.*[0-9])          assert that at least one digit is present
    (?=.*[A-Z])          assert that at least one capital letter is present
    (?=.*[^a-zA-Z0-9])   assert one special character
    .{6,}                then match any 6 or more characters
$                        end of the password
Tim Biegeleisen
  • 502,043
  • 27
  • 286
  • 360
  • Sorry, started typing mine in mobile before I realized you posted. Only difference is how we interpret the six characters thing. – Mad Physicist May 07 '19 at 02:04
  • FWIW, I think your interpretation is more intuitively correct, but mine is what OP had coded originally. – Mad Physicist May 07 '19 at 02:07
  • @MadPhysicist I also posted this from a mobile phone :-) – Tim Biegeleisen May 07 '19 at 02:15
  • This is great but it might cause backtracks. IMHO, something like `(?=\D*\d)(?=[^A-Z]*[A-Z])(?=\w*\W).{6,}` will give better performance. – cem May 07 '19 at 02:31
  • @cem I disagree, and the lookaheads I use should not backtrack. And I prefer my version to what you used. – Tim Biegeleisen May 07 '19 at 02:33
  • It's that time of day :). Speaking of backtracking, I've added the equivalent lookbehind approach to pretend like our answers are different. – Mad Physicist May 07 '19 at 03:04
  • @TimBiegeleisen It has to backtrack internally or it will not be capturing anything because of the star. There's actually no difference between `.*[0-9]` and `(?=.*[0-9])`, both of these has to eat all the characters and then start to backtrack, except when engine leaves the lookahead, it'll forget about it. [example](https://regex101.com/r/w7EMyq/1) – cem May 07 '19 at 03:28
  • @cem I get it :-) We could also just make the dots lazy, I think, e.g. use `(?=.*?[0-9])`. But, I typically don't see your suggestion being used in practice. The thing is, the lookaheads at most require just one scan of the input, which is linear and not really a big penalty. – Tim Biegeleisen May 07 '19 at 03:35
  • Thank you Tim! You couldn't have made it more clear and easy to understand, and your solution has worked! Thank you, as well, to M.P! – Troy May 09 '19 at 19:31
1

This could be done via lookaheads. Each criterion could be checked by lookahead this way:

(?=.*[A-Z])(?=(?:.*[A-Za-z]){6,})(?=(?:.*[0-9]))(?=(?:.*[^a-zA-Z0-9])).*

You can use re.match and re.fullmatch in addition to re.search for the validator.

An equivalent expression can be obtained using lookbehinds:

.*(?<=.*[A-Z])(?<=(?:.*[A-Za-z]){6,})(?<=(?:.*[0-9]))(?<=(?:.*[^a-zA-Z0-9]))

You can even mix and match e.g.:

(?=.*[A-Z])(?=(?:.*[A-Za-z]){6,}).*(?<=(?:.*[0-9]))(?<=(?:.*[^a-zA-Z0-9]))

Functionally, the approaches are all equivalent. The differences are mostly aesthetic, although of course there may be implementation details that cause small timing differences as well.

Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
  • Variable width lookbehinds are only supported by very few languages (e.g. C#). In general, they are considered bad and run the risk of backtracking problems. – Tim Biegeleisen May 07 '19 at 03:12
  • @Tim. I only understand regex at a very high level (jack of all trades, ...). Do you happen to know of a good place to read more? – Mad Physicist May 07 '19 at 03:14
  • If i had to recommend a single site, it would be [rexegg](http://www.rexegg.com/). But, regex is just something you pick up as you go along. There is no one stop shop for it. – Tim Biegeleisen May 07 '19 at 03:18
  • Thanks for the link. I've learned a lot even from just a cursory skim. Just part of going along. – Mad Physicist May 07 '19 at 03:25