There are two issues that need a fix:
\W
also matches whitespaces, [\W\s]
is equalt to \W
. Thus, /[^\W\s]/
should be just /\w/
\W
does not match underscores. When you require a special character and an underscore is treated as a special character, you need to use a [\W_]
character class
Note also, that regexps used with RegExp#test
should never be used with a g
flag, it might lead to issues like this (not the case here, but as a best practice). Also, \w
matches any lower- and uppercase ASCII letters, so not need to use a case insensitive i
modifier here.
So, you may use
return /\w/.test(value) // match any wordCharacter
&& /[a-z]/.test(value) // has a lowercase letter
&& /[A-Z]/.test(value) // has a uppercase letter
&& /\d/.test(value) // has a digit
&& /^[^\W_]*[\W_]/.test(value) // has a specialChar
});
The ^[^\W_]*[\W_]
pattern means
^
- match start of string
[^\W_]*
- 0 or more chars other than non-word chars or _
(i.e. 0 or more letters or digits)
[\W_]
- a non-word char or a _
char.