Regex for combination of given rules - javascript

I'm trying to write regex to validate the password for the given rule.
Passwords must be at least 8 characters in length and contain at least 3 of the following 4 types of characters:
lower case letters (i.e. a-z)
upper case letters (i.e. A-Z)
numbers (i.e. 0-9)
special characters (e.g. !##$&*)
I was going through this discussion and found this really great answer over there.
Now I'm trying to write regex for the mentioned requirements and I came up with the solution like this
^(?=.*[A-Z])(?=.*[!##$&*])(?=.*[0-9])(?=.*[a-z]).{8,}|
(?=.*[!##$&*])(?=.*[0-9])(?=.*[a-z]).{8,}|
(?=.*[A-Z])(?=.*[0-9])(?=.*[a-z]).{8,}|
(?=.*[A-Z])(?=.*[!##$&*])(?=.*[a-z]).{8,}|
(?=.*[A-Z])(?=.*[!##$&*])(?=.*[0-9]).{8,}$
and it is working perfect see rubular but I want to optimize these regex and I'm not sure If there are any way to simplify this.
Any suggestion will be appreciated.
Many thanks

Do yourself (and anyone who will work on that app in the future) a favour, and split the regexp in 4:
{
:lowercase => /regex_for_lowercase/,
:uppercase => /regex_for_uppercase/,
:digits => /regex_for_digits/,
:symbols => /regex_for_symbols/,
}
then count how many of these 4 rules the password matches. It will also give you the chance to show more helpful error message if the entered password does not validate.

Related

How to get the valid part of a regex match

I want to test if a user string is "ok so far", in that it might not be valid as a whole but it is a subset of a valid one.
I have a regex say ^[0-9]{4}-[0-9]{4}-[0-9]{4}-[0-9]$
such that "1234-1234-5678-5678" is valid
"1234-12" or even "1" does not match pattern but its a valid subset of a valid format, in other words the input is ok so far.
is there a neat way of doing this without making many many regexes, its friday.
Not sure if I understood well your problem, but I think you want to have something like this:
^([0-9]{4}-){1,3}[0-9]{1,4}$
Working demo
This will match set of 4 digits and can have the last set from 1 to 4 digits
You can also shorten your regex with:
^(\d{4}-){1,3}\d{1,4}$
You could possibly use one final regex for validation of the form you currently have, and a on the fly regex for the user input being valid for each subset.
My idea would be to have ([0-9]{1,4}-)+
For your case this will check as one types:
/^(\d(\d(\d(\d(-(\d(\d(\d(\d(-(\d(\d(\d(\d(-(\d)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?$/
This regex will match key for key as you type, although it is a little cumbersome.
^([0-9]{1,4}|[0-9]{4}-[0-9]{0,4}|[0-9]{4}-[0-9]{4}-[0-9]{0,4}|[0-9]{4}-[0-9]{4}-[0-9]{4}-[0-9]{0,4})$
Here is a live example

My regex that should only accept latin-based characters is acting strangely

I've got a regex written to the best of my ability that allows the latin character set only with the option of a '-' that, if included MUST be followed by at least one other latin character.
My RegEx:
[\u00BF-\u1FFF\u2C00-\uD7FFA-Za-z]+(?:[-]?[\u00BF-\u1FFF\u2C00-\uD7FFA-Za-z]+)
I came to this after reading a few posts and rereading the manual to figure out the best way to approach this. This check is attached to a text field where a user types only their first name and then submits.
It works okay but there is certainly room for improvement.
Examples:
Tom // passes
Éve // passes
John-Paul // passes
2pac // passes and removes numbers (not really what I want)
John316 // passes and removes numbers (not really what I want)
What I would REALLY want to happen is a fail on those last two checks.
How would I revise it to get the outcome I'd like?
You need to anchor the regex by adding ^ at the start and $ at the end. That way you will not let any other symbols in the input string.
I also suggest enhancing the pattern by moving ? from after hyphen to the end (that will make regex execution linear as the hyphen has no quantifier and is required, thus, limiting backtracking):
^[\u00BF-\u1FFF\u2C00-\uD7FFA-Za-z]+(?:-[\u00BF-\u1FFF\u2C00-\uD7FFA-Za-z]+)?$
See regex demo.
JS snippet:
console.log(/^[\u00BF-\u1FFF\u2C00-\uD7FFA-Za-z]+(?:-[\u00BF-\u1FFF\u2C00-\uD7FFA-Za-z]+)?$/.test('Éve')); //=> true
console.log(/^[\u00BF-\u1FFF\u2C00-\uD7FFA-Za-z]+(?:-[\u00BF-\u1FFF\u2C00-\uD7FFA-Za-z]+)?$/.test('John-Paul')); // => true
console.log(/^[\u00BF-\u1FFF\u2C00-\uD7FFA-Za-z]+(?:-[\u00BF-\u1FFF\u2C00-\uD7FFA-Za-z]+)?$/.test('John316')); // => false

Rewrite regex to accept conditional terms

^([a-z0-9_\.-])+#[yahoo]{5}\.([com]{3}\.)?[com]{3}$
this currently matches xxxx#yahoo.com , how can I rewrite this to match some additional domains? for example, gmail.com and deadforce.com. I tried the following but it did not work, what am I doing wrong?
^([a-z0-9_\.-])+#[yahoo|gmail|deadforce]{5,9}\.([com]{3}\.)?[com]{3}$
Thank you in advance!
Your regex doesn't say what you think it says.
^([a-z0-9_\.-])+#[yahoo]{5}\.([com]{3}\.)?[com]{3}$
Says any characters a-z, 0-9, ., - one or more times.
That later part where you are trying match yahoo.com is incorrect. It says y, a, h, or o, any of those characters are allowed 5 times. Same with the com so aaaaa.ooo would be valid here. I'm not sure what the ([com]{3}\.)?[com]{3} was trying to say but I presume you wanted to check for .com.
See character classes documentation here, http://www.regular-expressions.info/charclass.html.
What you want is
^([a-z0-9_.\-])+#yahoo\.com$
or for more domains use grouping,
^([a-z0-9_.\-])+#(yahoo|gmail|deadforce)\.com$
You haven't stated what language you are using so a real demo can't be given.
Functional demo, https://jsfiddle.net/qa9x9hua/1/
Email validation is a notoriously difficult problem, and many people have failed quite horribly at trying to validate them themselves.
Filter var has a filter just for emails. Use that to check for email address validity. See http://php.net/manual/en/function.filter-var.php
if (filter_var('bob#example.com', FILTER_VALIDATE_EMAIL)) {
// Email is valid
}
There's probably no downside to doing the domain check the easy way. Just check for the domain strings in the email address. e.g.
if (
filter_var($email, FILTER_VALIDATE_EMAIL) &&
preg_match("/#(yahoo|gmail|deadforce)\.com/", $email)
) {
// Email is valid
}
In terms of your original regular expression, quite a lot of it was incorrect, which is why you were having trouble changing it.
regexper shows what you've created.
([a-z0-9_\.-])+ should be [a-z0-9_\.-]+ or ([a-z0-9_\.-]+)
The () are only capturing results in this section. If you want results move the brackets, if not remove them.
[yahoo]{5} should be yahoo
That's matching 5 characters that are one of y,a,h,o so it would match hayoo etc.
\.([com]{3}\.)?[com]{3} should be \.com
Dunno what this was trying to accomplish but you only wanted .com
Take a look at http:// www.regular-expressions.info /tutorial.html for a guide to regular expressions

Need regex to match unformatted phone number syntax

I need a regex for Javascript that will match a phone number stripped of all characters except numbers and 'x' (for extension). Here are some example formats:
12223334444
2223334444
2223334444x5555
You are guaranteed to always have a minimum of 10 numerical digits, as the leading '1' and extension are optional. There is also no limit on the number of numerical digits that may appear after the 'x'. I want the numbers to be split into the following backreferences:
(1)(222)(333)(4444)x(5555)
The parenthesis above demonstrate how I want the number to be split up into backreferences. The first set of parenthesis would be assigned to backreference $1, for example.
So far, here is what I've come up with for a regex. Keep in mind that I'm not really that great with regex, and regexlib.com hasn't really helped me out in this department.
(\d{3})(\d{3})(\d{4})
The above regex handles the 2nd case in my list of example test cases in my first code snippet above. However, this regex needs to be modified to handle both the optional '1' and extension. Any help on this? Thanks!
Regex option seems perfectly fine to me.
var subject = '2223334444';
result = subject.replace(/^1?(\d{3})(\d{3})(\d{4})(x\d+)?$/mg, "1$1$2$3$4");
alert(result);
if(!result.match(/^\d{11}(?:x\d+)?/))
alert('The phone number came out invalid. Perhaps it was entered incorrectly');
This will say 12223334444 when there is no extension
I expect you want to tweak this out some, let me know how it should be.
If I were you, I would not go with a regular expression for this — it would cause more headaches than it solved. I would:
Split the phone number on the "x", store the last part in the extension.
See how long the initial part is, 9 or 10 digits
If it's 10 digits, check that the first is a 1, slice it off, and then continue with the 9-digit process:
If it's 9 digits, split it up into 3-3-4 and split them into area code, exchange, number.
Validate the area code and exchange code according to the rules of the NANP.
This will validate your phone number and be much, much easier and will make it possible for you to enforce rules like "no X11 area codes" or "no X11 exchange codes" more-easily — you'd have to do this anyway, and it's probably easier to just use plain string manipulation to split it into substrings.
I did a bit more testing and here's a solution I've found. I haven't found a case where this breaks yet, but if someone sees something wrong with it please let me know:
(1)?(\d{3})(\d{3})(\d{4})(?:x(\d+))?
Update:
I've revised the regex above to handle some more edge cases. This new version will fail completely if something unexpected is present.
(^1|^)(\d{3})(\d{3})(\d{4})($|(?:x(\d+))$)
My regex is:
/\+?[0-9\-\ \(\)]{10,22}/g

Why is my RegExp construction not accepted by JavaScript?

I'm using a RegExp to validate some user input on an ASP.NET web page. It's meant to enforce the construction of a password (i.e. between 8 and 20 long, at least one upper case character, at least one lower case character, at least one number, at least one of the characters ##!$% and no use of letters L or O (upper or lower) or numbers 0 and 1. This RegExp works fine in my tester (Expresso) and in my C# code.
This is how it looks:
(?-i)^(?=.{8,20})(?=.*[2-9])(?=.*[a-hj-km-np-z])(?=.*[A-HJ-KM-NP-Z])
(?=.*[##!$%])[2-9a-hj-km-np-zA-HJ-KM-NP-Z##!$%]*$
(Line break added for formatting)
However, when I run the code it lives in in IE6 or IE7 (haven't tried other browsers as this is an internal app and we're a Microsoft shop), I get a runtime error saying 'Syntax error in regular expression'. That's it - no further information in the error message aside from the line number.
What is it about this that JavaScript doesn't like?
Well, there are two ways of defining a Regex in Javascript:
a. Through a Regexp object constructor:
var re = new RegExp("pattern","flags");
re.test(myTestString);
b. Using a string literal:
var re = /pattern/flags;
You should also note that JS does not support some of the tenets of Regular Expressions. For a non-comprehensive list of features unsupported in JS, check out the regular-expressions.info site.
Specifically speaking, you appear to be setting some flags on the expression (for example, the case insensitive flag). I would suggest that you use the /i flag (as indicated by the syntax above) instead of using (?-i)
That would make your Regex as follows (Positive Lookahead appears to be supported):
/^(?=.{8,20})(?=.*[2-9])(?=.*[a-hj-km-np-z])(?=.*[A-HJ-KM-NP-Z])(?=.*[##!$%])[2-9a-hj-km-np-zA-HJ-KM-NP-Z##!$%]*$/i;
For a very good article on the subject, check out Regular Expressions in JavaScript.
Edit (after Howard's comment)
If you are simply assigning this Regex pattern to a RegularExpressionValidator control, then you will not have the ability to set Regex options (such as ignore case). Also, you will not be able to use the Regex literal syntax supported by Javascript. Therefore, the only option that remains is to make your pattern intrinsically case insensitive. For example, [a-h] would have to be written as [A-Ha-h]. This would make your Regex quite long-winded, I'm sorry to say.
Here is a solution to this problem, though I cannot vouch for it's legitimacy. Some other options that come to mind may be to turn of Client side validation altogether and validate exclusively on the Server. This will give you access to the full Regex flavour implemented by the System.Text.RegularExpressions.Regex object. Alternatively, use a CustomValidator and create your own JS function which applies the Regex match using the patterns that I (and others) have suggested.
I'm not familiar with C#'s regular expression syntax, but is this (at the start)
(?-i)
meant to turn the case insensitivity pattern modifier on? If so, that's your problem. Javascript doesn't support specifying the pattern modifiers in the expression. There's two ways to do this in javascript
var re = /pattern/i
var re = new RegExp('pattern','i');
Give one of those a try, and your expression should be happy.
As Cerberus mentions, (?-i) is not supported in JavaScript regexps. So, you need to get rid of that and use /i. Something to keep in mind is that there is no standard for regular expression syntax; it is different in each language, so testing in something that uses the .NET regular expression engine is not a valid test of how it will work in JavaScript. Instead, try and look for a reference on JavaScript regular expressions, such as this one.
Your match that looks for 8-20 characters is also invalid. This will ensure that there are at least 8 characters, but it does not limit the string to 20, since the character class with the kleene-closure (* operator) at the end can match as many characters as provided. What you want instead is to replace the * at the end with the {8,20}, and eliminate it from the beginning.
var re = /^(?=.*[2-9])(?=.*[a-hj-km-np-z])(?=.*[A-HJ-KM-NP-Z])(?=.*[##!$%])[2-9a-hj-km-np-zA-HJ-KM-NP-Z##!$%]{8,20}$/i;
On the other hand, I'm not really sure why you would want to restrict the length of passwords, unless there's a hard database limit (which there shouldn't be, since you shouldn't be storing passwords in plain text in the database, but instead hashing them down to something fixed size using a secure hash algorithm with a salt). And as mentioned, I don't see a reason to be so restrictive on the set of characters you allow. I'd recommend something more like this:
var re = /^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[##!$%])[a-zA-Z0-9##!$%]{8,}$/i;
Also, why would you forbid 1, 0, L and O from your passwords (and it looks like you're trying to forbid I as well, which you forgot to mention)? This will make it very hard for people to construct good passwords, and since you never see a password as you type it, there's no reason to worry about letters which look confusingly similar. If you want to have a more permissive regexp:
var re = /^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[##!$%]).{8,}$/i;
Are you enclosing the regexp in / / characters?
var regexp = /[]/;
return regexp.test();
(?-i)
Doesn't exist in JS Regexp. Flags can be specified as “new RegExp('pattern', 'i')”, or literal syntax “/pattern/i”.
(?=
Exists in modern implementations of JS Regexp, but is dangerously buggy in IE. Lookahead assertions should be avoided in JS for this reason.
between 8 and 20 long, at least one upper case character, at least one lower case character, at least one number, at least one of the characters ##!$% and no use of letters L or O (upper or lower) or numbers 0 and 1.
Do you have to do this in RegExp, and do you have to put all the conditions in one RegExp? Because those are easy conditions to match using multiple RegExps, or even simple string matching:
if (
s.length<8 || s.length>20 ||
s==s.toLowerCase() || s==s.toUpperCase() ||
s.indexOf('0')!=-1 || s.indexOf('1')!=-1 ||
s.toLowerCase().indexOf('l')!=-1 || s.toLowerCase().indexOf('o')!=-1 ||
(s.indexOf('#')==-1 && s.indexOf('#')==-1 && s.indexOf('!')==-1 && s.indexOf('%')==-1 && s.indexOf('%')==-1)
)
alert('Bad password!');
(These are really cruel and unhelpful password rules if meant for end-users BTW!)
I would use this regular expression:
/(?=[^2-9]*[2-9])(?=[^a-hj-km-np-z]*[a-hj-km-np-z])(?=[^A-HJ-KM-NP-Z]*[A-HJ-KM-NP-Z])(?=[^##!$%]*[##!$%])^[2-9a-hj-km-np-zA-HJ-KM-NP-Z##!$%]{8,}$/
The [^a-z]*[a-z] will make sure that the match is made as early as possible instead of expanding the .* and doing backtracking.
(?-i) is supposed to turn case-insensitivity off. Everybody seems to be assuming you're trying to turn it on, but that would be (?i). Anyway, you don't want it to be case-insensitive, since you need to ensure that there are both uppercase and lowercase letters. Since case-sensitive matching is the default, prefacing a regex with (?-i) is pointless even in those flavors (like .NET) that support inline modifiers.

Categories