REGEX to validate password that can't contain some caracters - php

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

Related

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.

Update a regex that matches twitter like mentions to allow for dots

I have already found helpful answers for a regex that matches twitter like username mentions in this answer and this answer
(?<=^|(?<=[^a-zA-Z0-9-_\.]))#([A-Za-z]+[A-Za-z0-9_]+)
(?<=^|(?<=[^a-zA-Z0-9-_\.]))#([A-Za-z]+[A-Za-z0-9-_]+)
However, I need to update this regex to also include usernames that has dots.
One or more dots are allowed in a username.
The username must not start or end with a dot.
No two consecutive dots are allowed.
Example of a matched string:
#valid.user.name
^^^^^^^^^^^^^^^^
Examples of non-matched strings:
#.user.name // starts with a dot
#user.name. // ends with a dot
#user..name // has two consecutive dots
You can use this refactored regex:
(?<=[^\w.-]|^)#([A-Za-z]+(?:\.\w+)*)$
RegEx Demo
RegEx Details:
(?<=[^\w.-]|^): Lookbehind to assert that we have start of line or any non-word, non-dot, non-hyphen character before current position
#: Match literal `#1
(: Start capture group
[A-Za-z]+: Match 1+ ASCII letters
(?:\.\w+)*: Match 0 or more instances of dot followed 1+ word characters
): End capture group
$: End
The (?<=^|(?<=[^a-zA-Z0-9-_\.])) is a positive lookbehind that requires a match to be at the start of the string or right after an alphanumeric, -, _, ., you may write it in a more compact way as (?<![\w.-]), a negative lookbehind.
Next, ([A-Za-z]+[A-Za-z0-9_]+) captures 1+ ASCII letters and then 1+ ASCII letters or/and underscores. You seem to make sure the first char is a letter, then any number of sequences of . and 1+ word chars are allowed, that is, you may use [A-Za-z]\w*(?:\.\w+)*.
As you do not want to match it if there is a . right after the expected match, you need to set a lookahead that will require a space or end of string, (?!\S).
So, combining it, you can use
'~(?<![\w.-])#([A-Za-z]\w*(?:\.\w+)*)(?!\S)~'
See the regex demo
Details
(?<![\w.-]) - no letters, digits, _, . and - immediately to the left of the current location are allowed
# - a # char
([A-Za-z]\w*(?:\.\w+)*) - Group 1:
[A-Za-z] - an ASCII letter
\w* - 0+ letters, digits, _
(?:\.\w+)* - 0+ sequences of
\. - dot
\w+ - 1+ letters, digits, _
(?!\S) - whitespace or end of string are required immediately to the right of the current location.
EDIT: Simpler version (same result)
^#[a-zA-Z](\.?[\w-]+)*$
Original
Another one:
^#[a-zA-Z][a-zA-Z_-]?(\.?[\w\d-]+){0,}$
^# starts with #
[a-zA-Z] first char
[a-zA-Z_-]? match a-zA-Z_- 0 or more times
( start group
\.? match . (optional)
[\w\d-]+ match a-zA-Z0-9-_ 1 or more times
) end group
{0,} repeat group 0 to infinite times
$ end
Tests
valid:
#validusername
#valid.user.name
#valid-user-name
#valid_user-name
#valid-user123_name
#a.valid-user123_name
not valid:
#-invalid.user
#_invalid.user
#1notvalid-user_123name33
#.user.name
#user.name.
#user..name

How do grab words that start and end with double percent signs?

I am really bad at regex and I am trying to do the following:
How do I get all strings that starts and end with %%.
If these words appear in a string I want to be able to grab them: %%HELLO_WOLD%%, %%STUFF%%
Here's what I came up with so far: %%[a-zA-Z0-9]\w+
You could use anchors to assert the start ^ and the end $ of the line and match zero or more times any character .* or if there must be at least one character your might use .+
^%%.*%%$
Or instead of .* you could add your character class [a-zA-Z0-9]+ which will match lower and uppercase characters and digits or use the \w+ which will match a word character.
Note that the character class [a-zA-Z0-9] does not match an underscore and \w does.
If you want to find multiple matches in a string you might use %%\w+%%. This will also match %%HELLO_WOLD%% in %%%%%HELLO_WOLD%%%.
If there should be only 2 percentage signs at the beginning and at the end, you could use a positive lookahead (?= and positive lookbehind (?<= to assert that what is before and after the 2 percentage signs is not a percentage sign or are the start ^ or end $ of the string.
(?<=^|[^%])%%\w+%%(?=[^%]|$)

Regex to match numbers only if alphabets are present

I require a regex to match the string in the following way:
#1234abc : Should get matched
#abc123 : Should get matched
#123abc123 : Should get matched
#123 : Should not get matched
#123_ : Should not get matched
#123abc_ : Should get matched
This implies that it should only get matched if the string contains numbers or underscore along with alphabets. Only numbers/underscore should not get matched. Any other special characters should not get matched either.
This regex is basically to get hashtags from string. I have already tried the following but it didn't worked well for me.
preg_match_all('/(?:^|\s)#([a-zA-Z0-9_]+$)/', $text, $matches);
Please suggest something.
If you need to match hashtags in the format you specified in a larger string, use
(?<!\S)#\w*[a-zA-Z]\w*
See the regex demo
Details:
(?<!\S) - there must be a start of string or a whitespace before
# - a hash symbol
\w* - 0+ word chars (that is, letters, digits or underscore)
[a-zA-Z] - a letter (you may use \p{L} instead)
\w* - 0+ word chars.
Other alternatives (that may appear faster, but are a bit more complex):
(?<!\S)#(?![0-9_]+\b)\w+
(?<!\S)#(?=\w*[a-zA-Z])\w+
The point here is that the pattern basically matches 1+ word chars preceded with # that is either at the string start or after whitespace, but (?![0-9_]+\b) negative lookahead fails all matches where the part after # is all digits/underscores, and the (?=\w*[a-zA-Z]) positive lookahead requires that there should be at least 1 ASCII letter after 0+ word chars.
You can use this Regex:
((.*?(\d+)[a-zA-Z]+.*)|(.*[a-zA-Z]+(\d+).*)).
Access it here: http://regexr.com/3ef6q
see it working:
Do:
^(?=.*[A-Za-z])[\w_]+$
[\w_]+ matches one or more of letters, digits, _
The zero width positive lookahead pattern, (?=.*[A-Za-z]), makes sure the match contains at least one letter
Demo

Regex for password grading

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

Categories