password validation using javascript - javascript

I need to match a password field using javascript with the following requirements:
Should be alpha numaric with at least one special character.
no spaces to be allowed
should be minimum 10 char and max 20 chars.
No repeate of char more than 2 times.
~,'.:;^| are not allowed
I have a regex
var password = /^(?=.[0-9])(?=.[!##$%^&])[a-zA-Z0-9!##$%^&]{10,20}$/;
how can i solve this?

This might be the required regex
^(?=.*[!##$%^&])(?!.*(.).*\1.*\1)[A-Za-z\d!##$%^&|]{10,20}$
(?=.*[!##$%^&]) ensures at least one occurrence of the listed characters.
(?!.*(.).*\1.*\1) ensures no character is repeated more than twice.
[A-Za-z\d!##$%^&|]{10,20} matches 10-20 occurrence of characters from the character class.

I would write separate rules (probably using regex for all of them - for consistency - unless performance is a great concern) that each relate directly to a rule on your list.
The code
var pw = "asddfak#kjg";
/* Should be alpha numaric with at least one special character. */
console.log(null !== pw.match(/[#+#$]/));
/* no spaces to be allowed */
console.log(null !== pw.match(/^\S+$/));
/* should be minimum 10 char and max 20 chars. */
console.log(null !== pw.match(/^.{10,20}$/));
/* No repeate of char more than 2 times. */
console.log(null === pw.match(/(.)(.*\1){2}/));
/* ~,'.:;^| are not allowed */
console.log(null !== pw.match(/^[^~,'.:;^|]+$/));
Although it is possible to make the regex more concise, I think it is much more maintainable to make the rules more literal to your intent. If performance is a significant issue (usually not for this kind of thing) then I would avoid regex, and implement the rules using string methods.
Regex Explained
/ // start regex pattern
[ // open character class
#+#$ // match one of these `special` characters
] // close character class
/ // end regex pattern
/ // start regex pattern
^ // start matched string
\S+ // one or more (`+`) not spaces (`\S`)
$ // end matched string
/ // end regex pattern
/ // start regex pattern
^ // start matched string
.{10,20} // between 10 and 20 of any character (`.`)
$ // end matched string
/ // end regex pattern
/ // start regex pattern
(.) // any character captured as group 1
(.*\1){2} // followed by zero or more of anything (`\.*`) and then the captured group 1 (`\1`) two times (`{2}`)
/ // end regex pattern
/ // start regex pattern
^ // start matched string
[ // open character class
^~,'.:;^| // not (`^`) one of these characters
]+ // close character class
$ // end matched string
/ // end regex pattern
p.s. you should keep a lot of comments with regex you use, because unlike books, they are much easier written than read

This should work:
/^(?=.*?[!##$%^&])(?:([a-zA-Z0-9!##$%^&])(?!.*?\1.*?\1)){10,20}$/
(if by repeat more than 2 times you mean the same character can't appear thrice)
Explanation:
1st condition: at the very beginning, we'll go through the whole string a first time until we find a special character, as soon as we have it, we stop, if we don't, it fails (Source): (?=.*?[!##$%^&])
2nd condition: nothing to do, [a-zA-Z0-9!##$%^&] doesn't allow spaces anyway
3rd condition: quantifier: {10,20}
4th condition: the subtle one: as we get through the string, for each character captured, we check the it's not repeated twice more (same source): (?!.*?\1.*?\1)
5th condition: same as whitespaces

based on your 5 things in your requirements this is exact pattern you need
^(?=.*[!##$%^&])(?!.*(.).*\1.*\1)[^\s~,'.:;^|]{10,20}$

Related

Regex to allow * only after a certain position in the string

I have an input field in the UI which must satisfy the following three conditions.
The input string can be a max of 20 chars long and will be alphanumeric.
However it can have * but only after 6th character, no other special characters allowed.
Eg. Abc123* or Abc1234* or just Abc1234(until 20 chars)
The overall length of string is 20 chars but as soon as we encounter * we should not allow any further characters
I understand the 3rd condition can be a bit too much of an ask for regex and I should be able to handle that using javascript.
However I at least want to get the first 2 conditions resolved using regex.
I have tried few stuffs below but they don’t give the desired results:
export function formatInput(value) {
return value
.replace(/[^\w*]|_/g, '')
.replace(new RegExp('(^[\\w]{6})([\\w*]{14}$)’, 'g'), '$1');
}
I tried to tweak few things, like if I remove the first replace statement it doesn’t filter out any special characters at all.
Also in the below case it restricts me to enter * as 7th character before allowing me to proceed further which is also incorrect.
export function formatInput(value) {
return value
.replace(/[^\w*]|_/g, '')
.replace(new RegExp('(^[\\w]{6})[\\w]', 'g'), '$1')
.replace(/(\..*)\./g, '$1')
.replace(new RegExp('(\\*[\\w]{14}).', 'g'), '$1');
}
I am trying to enhance my knowledge about regex, so my above attempts might not be correct, any help will be highly appreciated.
I'm a bit confused with your attempt to replace, so let me just share a pattern that should tick the 3 boxes you described:
^(?!.{21}|.{1,5}\*)[A-Za-z\d]+\*?$
See the online demo
^ - Start line anchor.
(?!.{21}|.{1,5}\*) - Negative lookahead with alternation to prevent position is followed by 21 characters or 1-5 characters before the asterisks.
[A-Za-z\d]+ - 1+ Alphanumeric chars.
\*? - An optional asterisks.
$ - End line anchor.
Note that you could also use case-insensitive flag as an alternative and use ^(?!.{21}|.{1,5}\*)[A-Z\d]+\*?$.
Something like this would work:
/^(?:[a-z\d]{6,19}\*|[a-z\d]{1,20})$/gmi
^ - start line anchor
(?: - start non-capturing group
[a-z\d]{6,19}\* - we can have 6 to 19 alphanums followed by one asterisk
| - boolean or
[a-z\d]{1,20} - we can have 1 to 20 alphanums
) - end non-capturing group
$ - end line anchor
/gmi - flags: global, multiline, case-insensitive
g and m are only needed for regex101 purposes so that you can test out multiple inputs at once
https://regex101.com/r/ytMlQO/1/
The following pattern satisfies all your conditions. This pattern assumes there is no other content in value aside from the password to be checked. I also share the concern about performing manipulations a la replace in a function that is supposed to be purely for verification, so I've written the function below to simply test to ensure conformance with the prescribed pattern.
const passwordPattern = /^[A-Za-z\d]{6}(?:[A-Za-z\d]|\*(?!.+)){0,14}$/;
const checkPassword = value => passwordPattern.test(value);
console.log(checkPassword("Abc123")); // true
console.log(checkPassword("Abc123*")); // true
console.log(checkPassword("Abc12*")); // false - asterisk appears before position 6
console.log(checkPassword("Abc123*4")); // false - other characters appear after asterisk
console.log(checkPassword("123456789012345678901")); // false - >20 characters in length
Regex101

RegEx - contain specific number after period

I have strings similar to; First Half Goals 1.5/2. The text at the beginning can be anything so cannot depend on that as part of the RegEx as it varies. What I want to do is to match the number sequence at the end. Test samples would be:
5
0.5/1
2.5/3
147
The sequence can either contain a slash or it cannot. If it contains a slash, there must be a value after it - either integer or decimal. The value before the decimal (if one is present) can be any number of digits - \d+ - but the value after should must be 0 or 5 - (0|5). The 1st value before the slash (/) is either an integer or a decimal. If the sequence contains a slash, then the number after is also either a integer or a decimal. All values are positive.
The main point of this RegEx is that I need it to only match once. The was the RegEx I was using:
(\d(\.(0|5))?\/\d(\.(0|5)))|(\d\.(0|5))|(\d)
The issue with the regex above is that the example string I use; First Half Goals 1.5/2 matched twice. Once on the 1.5 & the 2nd on the 2. I have now altered it to be this:
\d+(\.(0|5))?(\/?\d+(\.(0|5))?)?
This is slightly better but if I give the test sample; 1.6/2, it will match 6/2. This will be because the decimal section on the former number is optional. I'm not sure if a lookbehind would come in handy here, I don't have much experience with them. Sadly the text beforehand is so unpredictable otherwise I could trim the string to only get the wanted substring & then match from the start of the string but can't do that. An outline of what should match & what should not:
1 // Match
5.5 // Match
7.8 // No Match
0/0.5 // Match
147/147.5 // Match
2. // No Match
6.5/ // No Match
7.0/8 // Match
10.0 // Match
1./2.5 // No Match
5./6 // No Match
/157 // No Match
/4.5 // No Match
I've tried to explain as best I could but if you need more details then I'll provide them
In Node.js, RegExp supports lookbehinds and you may use
/\b(?<!\d\.|\/)\d+(?:\.[05])?(?:\/\d+(?:\.[05])?)?$/
See the regex demo
Details
\b - word boundary
(?<!\d\.|\/) - no digit + dot or a slash are allowed immediately to the left of the current location
\d+ - one or more digits
(?:\.[05])? - an optional sequence of
\. - a dot
[05] - 0 or 5
(?:\/\d+(?:\.[05])?)? - an optional sequence of
\/\d+ - a / and 1+ digits
(?:\.[05])? - an optional sequence of a dot and then 0 or 5
$ - end of string.

Regex for given pattern

I have below test case
hello how are you // 1. Allow
hello how are you // 2. Not Allow
hello < // 3. Not Allow
for the following Rules:
Allow spaces at start and end
Not allow more than one space between words
Not allow angle brackets < >
I am trying the below:
^([^<> ]+ )+[^<> ]+$|^[^<> ]+$
This is working, but when giving spaces at start or end it is not allowing.
I assume that you use your regex to find matches in the whole
text string (all 3 lines together).
I see also that both your alternatives contain starting ^ and ending $,
so you want to limit the match to a single line
and probably use m regex option.
Note that [^...]+ expression matches a sequence of characters other than
placed between brackets, but it does not exclude \n chars,
what is probably not what you want.
So, maybe you should add \n in each [^...]+ expression.
The regex extended such a way is:
^([^<> \n]+ )+[^<> \n]+$|^[^<> \n]+$
and it matches line 1 and 2.
But note that the first alternative alone (^([^<> \n]+ )+[^<> \n]+$)
also does the job.
It you realy want that line 2 should not match, please specify why.
Edit
To allow any number of spaces at the begin / end of each line,
add * after initial ^ and before final $, so that the
regex (first alternative only) becomes:
^ *([^<> \n]+ )+[^<> \n]+ *$
But it still matches line 2.
Or maybe dots in your test string are actually spaces, but you wrote
the string using dots, to show the numer of spaces?
You should have mentioned it in your question.
Edit 2
Yet another possibility, allowing dots in place of spaces:
^[ .]*((?:[^<> .\n]+[ .])+[^<> .\n]+|[^<> .\n]+)[ .]*$
Details:
^[ .]* - Start of a line + a sequence of spaces or dots, may be empty.
( - Start of the capturing group - container for both alternatives of
stripped content.
(?:[^<> .\n]+[ .])+ - Alternative 1: A sequence of "allowed" chars ("word") +
a single space or dot (before the next "word", repeated a few times.
This group does not need to be a capturing one, so I put ?:.
[^<> .\n]+ - A sequence of "allowed" chars - the last "word".
| - Or.
[^<> .\n]+ - Alternative 2: A single "word".
) - End of the capturing group.
[ .]*$ - The final (possibly empty) sequence of spaces / dots + the
end of line.
Of course, with m option.

How to limit a string length

I have the following regex:
^[a-zA-Z_][\-_a-zA-Z0-9]*
I need to limit it's length to 39 characters. I tried the following but it didn't work:
^[a-zA-Z_][\-_a-zA-Z0-9]*{,38}
You just need to use a limited quantifier {0,38} and an end of string anchor $:
^[a-zA-Z_][-_a-zA-Z0-9]{0,38}$
^^^^^ ^
The syntax for the limited quantifiers is {min,max} where the max parameter is optional, but the minimum should be present. Without $ you may match 39 first characters in a much longer string.
You do not have to escape a hyphen when it is placed at the beginning of a character class (thus, I suggest removing it).
Also, you can further shorten the regex with an /imodifier:
/^[a-z_][-_a-z0-9]{0,38}$/i
or even
/^[a-z_][-\w]{0,38}$/i
Regarding the question from the comment:
wouldn't also that version work (^[a-zA-Z_][-_a-zA-Z0-9]){0,39}$ with 39 characters limit?
The regex matches
(^[a-zA-Z_][-_a-zA-Z0-9]){0,39} - 0 to 39 sequences of...
^ - start of the string
[a-zA-Z_] - a single character from the specified range
[-_a-zA-Z0-9] - a single character from the specified range
$ - end of string
So, you require a match to include sequences from the start of the string. Note a start of string can be matched only once. As you let the number of such sequences to be 0, you only match either the location at the end of the string or a 2 character string like A-.
Let's see what the regex does with the Word input. It mathces the start of string with ^, then W with [a-zA-Z_], then o with [-_a-zA-Z0-9]. Then the group ends, and that equals to matching the group once. Since we can match more sequences, the regex tries to match r with ^. It fails. So, the next position is retried and failed the same way, because d is not the ^ (start of string). And that way the end of string is matched because there is a 0 occurrences of ^[a-zA-Z_][-_a-zA-Z0-9] and there is an end of string $.
See regex demo
try
^[a-zA-Z_][\-_a-zA-Z0-9]{0,38}$
[0,38] means that number of instances of characters matching [\-_a-zA-Z0-9] could be 0 to 38.
I'm adding this in case you're limiting input field entry.
While not regex, I use this function and it works well (I will add that it's important to let the user know you're limiting the input length from UI/UX point of view):
limitLength: function(element, lengthOf){
var fieldLength = element.value.length;
if(fieldLength <= lengthOf){
return true;
} else {
var str = element.value;
str = str.substring(0, str.length - 1);
element.value = str;
}
}
Usage:
<input type="text" onInput="my.namespace.limitLength(this,39)">

Query on Javascript RegEx

I need a regex that allows 0-9, a-z, A-Z, hyphen, question mark and "/" slash characters alone. Also the length should be between 5 to 15 only.
I tried as follows, but it does not work:
var reg3 = /^([a-zA-Z0-9?-]){4,15}+$/;
alert(reg3.test("abcd-"));
length should be between 5 to 15 only
Is that why you have this?
{4,15}+
Just use {5,15}; it’s already a quantifier, and a + after it won’t work. Apart from that, the group isn’t necessary, but things should work.
/^[a-zA-Z0-9?/-]{5,15}$/
(I also added a slash character.)
This is what you need:
if (/^([a-z\/?-]{4,15})$/i.test(subject)) {
// Successful match
} else {
// Match attempt failed
}
REGEX EXPLANATION
^([a-z\/?-]{4,15})$
Options: Case insensitive
Assert position at the beginning of the string «^»
Match the regex below and capture its match into backreference number 1 «([a-z\/?-]{4,15})»
Match a single character present in the list below «[a-z\/?-]{4,15}»
Between 4 and 15 times, as many times as possible, giving back as needed (greedy) «{4,15}»
A character in the range between “a” and “z” (case insensitive) «a-z»
The literal character “/” «\/»
The literal character “?” «?»
The literal character “-” «-»
Assert position at the very end of the string «$»
Couple issues,
you need {5,15} instead of {4,15}+
need to include /
Your code can be rewritten as
var reg3 = new RegExp('^[a-z0-9?/-]{5,15}$', 'i'); // i flag to eliminate need of A-Z
alert(reg3.test("a1?-A7="));
Update
Let's not confuse can be with MUST be and concentrate on the actual thing I was trying to convey.
{4,15}+ part in /^([a-zA-Z0-9?-]){4,15}+$/ should be written as {5,15}, and / must be included; which will make your regexp
/^([a-zA-Z0-9?/-]){5,15}$/
which CAN be written as
/^[a-z0-9?/-]{5,15}$/i // i flag to eliminate need of A-Z
Also I hope everybody is OK with use of /i

Categories

Resources