Regex for password grading - php

I'm working on a regular expression grading the quality of the used password. The idea is that a password is considered mediocre if it contains ONLY 1 uppercase character OR atleast 6 uppercase characters. The password itself should be atleast 8 characters long.
Desired behavior:
Aaaaaaaa -> match
AAAAAAaa -> match
AAaaaaaa -> no match
I tried something like this:
(?=.*[A-Z]{1,1}|(?=.*[A-Z]{6,})).{8,}
Which doesn't do the trick because it also matches on AAaaaaaa. The problem is the first positive lookahead which allows 2-5 uppercase characters but i couldn't figure out how to avoid that.

You should restrict the first lookahead to only require 1 uppercase letter in the whole string. Just define the full string pattern as any non-uppercase letter(s) followed with 1 uppercase one, and then any number of non-uppercase letter characters are allowed.
If you plan to require 6 uppercase letters at a row, use
/^(?=[^A-Z]*[A-Z][^A-Z]*$|.*[A-Z]{6,}).{8,}$/
^^^^^^^^^^^^^^^^^^^^
See this regex demo
If these 6 uppercase letters can be scattered around the string, use
/^(?=[^A-Z]*[A-Z][^A-Z]*$|(?:[^A-Z]*[A-Z]){6,}).{8,}$/
^^^^^^^^^^^^^^^^^^^^
Where (?:[^A-Z]*[A-Z]){6,} searches for at least 6 occurrences of 0+ non-uppercase letter characters followed with an uppercase letter. See this regex demo.
If you need to support Unicode, add /u modifier at the end of the regex, and replace [A-Z] with \p{Lu}, [^A-Z] with \P{Lu}.
Also, it is recommended to use \A instead of ^ and \z instead of $ since it is password validation.
Another regex that is based on the logic suggested by bobble bubble:
^ # String start
(?=.{8,}$) # 8 or more characters other than a newline
(?:
[^A-Z]*[A-Z][^A-Z]* # a string with 1 uppercase letter only
| # or...
(?:[^A-Z]*[A-Z]){6} # 6 occ. of 0+ chars other than uppercase letters followed with 1 uppercase letter
.* # 0+ chars other than a newline
)
$ # string end
See the regex demo and as 1 line:
/^(?=.{8,}$)(?:[^A-Z\n]*[A-Z][^A-Z\n]*|(?:[^A-Z\n]*[A-Z]){6}.*)$/
See this demo.

Your .*[A-Z] will also consume uppers. Use exclusion between upper letters.
^(?=.{8})(?:([^A-Z]*[A-Z]){6}.*|(?1)[^A-Z]*$)
It checks if there is at least 6 or exactly 1 upper surrounded by non-upper.
(?=.{8}) The lookahead at start checks for at least 8 characters
(?1) is a reference to ([^A-Z]*[A-Z])
More explanation and demo at regex101

Ok. I think this is not a suitable criteria for strong passwords, but let's cocentrate on the question anyway: count the capital letters in a string.
I think this is really not easy to do using regexp. Does it need to be one? Then you should remove the php tag from the question...
PHP solution: I would just filter for the capital letters and count them afterwards.
$caps = strlen(preg_replace('/[^A-Z]+/', '', $pass)); // number of uppercase chars in `$pass`
$mediocre = strlen($pass) != 8 || $caps > 5 || $caps < 2;
// mediocre if $pass is not exactly 8 chars long and does not contain between 2 and 5 uppercase characters

Related

REGEX to validate password that can't contain some caracters

I need to check if a password match the following rules:
At least 8 characters (lenth)
One capital letter
One lower letter
One number
One special char
Can't contain '.' or '_' (tricky part)
For example:
Bft$ns2E => should match
H2od%^.,3 => should't match (notice the '.')
I tried this:
^(?=.*?[A-Z])(?=(.*[a-z]){1,})(?=(.*[\d]){1,})(?=(.*[\W]){1,})(?!.*\s).{8,}$
That satisfy all rules, except the last one ( Can't contain '.' or '_'). Regex are always a pain for me and can't figure out how to do this.
Thanks to all!
Your regex is on the right track. I would use:
^(?=.*?[A-Z])(?=.*[a-z])(?=.*\d)(?=.*\W)(?!.*[._]).{8,}$
This pattern says to:
^
(?=.*?[A-Z]) assert capital letter
(?=.*[a-z]) assert lowercase letter
(?=.*\d) assert digit
(?=.*\W) assert non word/special character
(?!.*[._]) assert NO dot or underscore
.{8,} match a password of length 8 or greater
$
Using the lookaheads like this (?=(.*[a-z]){1,}), you can omit the group with the quantifier {1,} as asserting it once in the string is enough.
If you don't want to match a space . or _ you can use a negated character class to match 8 or more times excluding those characters.
Using a negated character class as well in the lookahead assertions prevents unnecessary backtracking.
^(?=[^A-Z\r\n]*[A-Z])(?=[^a-z\r\n]*[a-z])(?=[^\d\r\n]*\d)(?=\w*\W)[^\s._]{8,}$
The pattern matches:
^ Start of string
(?=[^A-Z\r\n]*[A-Z]) Assert a char A-Z
(?=[^a-z\r\n]*[a-z]) Assert a char a-z
(?=[^\d\r\n]*\d) Assert a digit
(?=\w*\W) Assert a non word char
[^\s._]{8,} Match 8+ times any char except a whitespace char . or -
$ End of string
Regex demo

Validating password with Regular Expression

A task I'm working on requires a password to be validated with the following rules:
Must start with a capital letter (A-Z)
Have eight characters (minimum)
One of these characters must be a ! ^ or &
And password must end with a number.
This is the Regular Expression I have so far:
'/^\p{Lu}(?=.*[!^&])\d$.{8,}$/';
// Start with a capital letter: ^\p{Lu}
// At least 8 characters: .{8,}
// One of these characters must be a: (?=.*[!^&])
// Must end with a number: \d$
The expression for eight characters and a number work but the special character and capital letter doesn't work so I'm turning to the experts for this who could push me in the right direction.
The pattern already matches an uppercase char at the start, so it should be followed by 7 or more chars to make it at least 8 or more chars.
You can also match a digit at the end, and then you can match 6 or more chars before it.
If the pattern should have 8 characters minimum, you can use:
^\p{Lu}(?=[^!^&]*[!^&]).{6,}\d$
^ Start of string
\p{Lu} Match any uppercase letter
(?=[^!^&]*[!^&]) Positive lookahead, assert one of ! ^ &
.{6,} Match any char 6 or more times
\d$ Match a digit at the end of the string
Regex demo
Note that the . matches any char, including spaces.

Regex repeating letters

How can I not allow a user to enter a word with repeating letters I already have the case for special characters?
I have tried this and it works for the special characters allowed in the text.
^(?!.*([ \-])\1)\w[a-zA-z0-9 \-]*$
3 My Address--
Will not work (--)
This is what I am trying to do for the letters (?!.*([a-z])\1{4}) but it does not work it breaks the regex.
(?!.*([ \-])\1)(?!.*([a-z])\1{4})\w[a-zA-z0-9 \-]*$
It should prevent any repeating letters when they have been entered 4 times in a row for example this is for a address and as it stand I can enter.
3 My Adddddddddd
You need to use \2 backreference in the second lookahead, and mind using [a-zA-Z], not [a-zA-z] in the consuming part:
^(?!.*([ -])\1)(?!.*([A-Za-z])\2{3})\w[a-zA-Z0-9 -]*$
See the regex demo.
The first capturing group is ([ -]) in the first lookahead, the second lookahead contains the second group, thus, \2 is necessary.
As you want to filter out matches with at least 4 identical consecutive letters, you need ([A-Za-z])\2{3}, not {4}.
Also, if you plan to match a digit at the beginning, consider replacing \w with \d.
Regex details
^ - start of string
(?!.*([ -])\1) - no two identical consecutive spaces or hyphens allowed in the string
(?!.*([A-Za-z])\2{3}) - no four identical consecutive letters allowed in the string
\w - the first char should be a letter, digit or _
[a-zA-Z0-9 -]* - 0+ letters, digits, spaces or hyphens
$ - end of string.

Regex not working - minimum 1 uppercase, minimum 3 lowercase, minimum 1 special character from the defined group (more in description)

I need to create a regular expression with the next demands: Password need to have at least 8 characters and maximum 12 characters, at least 1 uppercase, at least 3 lowercase, at least 1 digit and at least 1 special character from the group (#*.!?$), without parentheses. The first character needs to be an uppercase or lowercase letter. Two consecutive same characters must not appear in the password.
I made this, but it doesn't work:
^(?=.{8,12}$)(([a-z]|[A-Z])(?=.*\d){1,}(?=.*[a-z]){3,}(?=.*[A-Z]){1,}(?=.*[!.?*$#])\2?(?!\2))+$
I tried to test it with Abcd123!, but it doesn't work. Can anyone explain where did I make a mistake, and what I actually did here?
You use a quantifier like {1,} for the lookahead which is not correct.
I think you meant to use the lookaheads like this:
^(?=.{8,12}$)(?=[^A-Z]*[A-Z])(?=\D*\d)(?=(?:[^a-z]*[a-z]){3})(?=[^\s#*.!?$]*[#*.!?$])(?!.*(.)\1)(?:[a-z]|[A-Z])[a-zA-Z0-9#*.!?$,]+$
About the pattern
^ Start of the string
(?=.{8,12}$) Assert lenght 8 - 12
(?=[^A-Z]*[A-Z]) Assert an uppercase char
(?=\D*\d) Assert a digit
(?=(?:[^a-z]*[a-z]){3}) Assert 3 lowercase chars
(?=[^\s#*.!?$]*[#*.!?$]) Assert special char
(?!.*(.)\1) Assert not 2 consecutive chars
(?:[a-z]|[A-Z]) Start with upper or lowercase char
[a-zA-Z0-9#*.!?$,]+ Match 1+ times any of the listed in the character class
$ Assert end of the string
Regex demo | Php demo

Password Regular expression with four criteria

I am trying to write a regular expression in PHP to ensure a password matches a criteria which is:
It should atleast 8 characters long
It should include at least one special character
It should include at least one capital letter.
I have written the following expression:
$pattern=([a-zA-Z\W+0-9]{8,})
However, it doesn't seem to work as per the listed criteria. Could I get another pair of eyes to aid me please?
Your regex - ([a-zA-Z\W+0-9]{8,}) - actually searches for a substring in a larger text that is at least 8 characters long, but also allowing any English letters, non-word characters (other than [a-zA-Z0-9_]), and digits, so it does not enforce 2 of your requirements. They can be set with look-aheads.
Here is a fixed regex:
^(?=.*\W.*)(?=.*[A-Z].*).{8,}$
Actually, you can replace [A-Z] with \p{Lu} if you want to also match/allow non-English letters. You can also consider using \p{S} instead of \W, or further precise your criterion of a special character by adding symbols or character classes, e.g. [\p{P}\p{S}] (this will also include all Unicode punctuation).
An enhanced regex version:
^(?=.*[\p{S}\p{P}].*)(?=.*\p{Lu}.*).{8,}$
A human-readable explanation:
^ - Beginning of a string
(?=.*\W.*) - Requirement to have at least 1 non-word character
OR (?=.*[\p{S}\p{P}].*) - At least 1 Unicode special or punctuation symbol
(?=.*[A-Z].*) - Requirement to have at least 1 uppercase English letter
OR (?=.*\p{Lu}.*) - At least 1 Unicode letter
.{8,} - Requirement to have at least 8 symbols
$ - End of string
See Demo 1 and Demo 2 (Enhanced regex)
Sample code:
if (preg_match('/^(?=.*\W.*)(?=.*[A-Z].*).{8,}$/u', $header)) {
// PASS
}
else {
# FAIL
}
Using positive lookahead ?= we make sure that all password requirements are met.
Requirements for strong password:
At least 8 chars long
At least 1 Capital Letter
At least 1 Special Character
Regex:
^((?=[\S]{8})(?:.*)(?=[A-Z]{1})(?:.*)(?=[\p{S}])(?:.*))$
PHP implementation:
if (preg_match('/^((?=[\S]{8})(?:.*)(?=[A-Z]{1})(?:.*)(?=[\p{S}])(?:.*))$/u', $password)) {
# Strong Password
} else {
# Weak Password
}
Examples:
12345678 - WEAK
1234%fff - WEAK
1234_44A - WEAK
133333A$ - STRONG
Regex Explanation:
^ assert position at start of the string
1st Capturing group ((?=[\S]{8})(?:.*)(?=[A-Z]{1})(?:.*)(?=[\p{S}])(?:.*))
(?=[\S]{8}) Positive Lookahead - Assert that the regex below can be matched
[\S]{8} match a single character present in the list below
Quantifier: {8} Exactly 8 times
\S match any kind of visible character [\P{Z}\H\V]
(?:.*) Non-capturing group
.* matches any character (except newline) [unicode]
Quantifier: * Between zero and unlimited times, as many times as possible, giving back as needed [greedy]
(?=[A-Z]{1}) Positive Lookahead - Assert that the regex below can be matched
[A-Z]{1} match a single character present in the list below
Quantifier: {1} Exactly 1 time (meaningless quantifier)
A-Z a single character in the range between A and Z (case sensitive)
(?:.*) Non-capturing group
.* matches any character (except newline) [unicode]
Quantifier: * Between zero and unlimited times, as many times as possible, giving back as needed [greedy]
(?=[\p{S}]) Positive Lookahead - Assert that the regex below can be matched
[\p{S}] match a single character present in the list below
\p{S} matches math symbols, currency signs, dingbats, box-drawing characters, etc
(?:.*) Non-capturing group
.* matches any character (except newline) [unicode]
Quantifier: * Between zero and unlimited times, as many times as possible, giving back as needed [greedy]
$ assert position at end of the string
u modifier: unicode: Pattern strings are treated as UTF-16. Also causes escape sequences to match unicode characters
Demo:
https://regex101.com/r/hE2dD2/1

Categories