Validate numbers, parenthesis and spaces only in jQuery validation - javascript

I am trying and failing hard in validating a phone number within jQuery validation. All I want is to allow a number like (01660) 888999. Looking around the net I find a million examples but nothing seems to work. Here is my current effort
$.validator.addMethod("phonenumber", function(value) {
var re = new RegExp("/[\d\s()+-]/g");
return re.test(value);
//return value.match("/[\d\s]*$");
}, "Please enter a valid phone number");

Bergi is correct that the way you are constructing the regular expression is wrong.
Another problem is that you are missing anchors and a +:
var re = /^[\d\s()+-]+$/;
Note though that a regular expression based solution will still allow some inputs that aren't valid phone numbers. You can improve your regular expression in many ways, for example you might want to require that there are at least x digits, for example.
There are many rules for what phone numbers are valid and invalid. It is unlikely you could encode all those rules into a regular expression in a maintainable way, so you could try one of these approaches:
Find a library that is able to validate phone numbers (but possibly not regular expression based).
If you need a regular expression, aim for something that is a close approximation to the rules, but doesn't attempt to handle all the special cases. I would suggest trying to write an expression that accepts all valid phone numbers, but doesn't necessarily reject all invalid phone numbers.
You may also want to consider writing test cases for your solution. The tests will also double as a form of documentation of which inputs you wish to accept and reject.

You need to use either a regex literal or a string literal in the RegExp constructor:
var re = /[\d\s()+-]/g;
// or
var re = new RegExp("[\\d\\s()+-]", "g");
See also Creating a Regular Expression.
Apart from that, you would need to use start- and end-of-string anchors to make sure that the regex matches the whole string, not only a part of it, and some repetition modifier to allow more than one character:
var re = /^[\d\s()+-]+$/g;

Another approach may be:
function(value) {
return /^\d+$/.test(value.replace(/[()\s+-]/g,''));
}
and if you want to check for the length of the number too, say it has to be a string with 10 digits:
function(value) {
return /^\d{10}$/.test(value.replace(/[()\s+-]/g,''));
}

Related

Unicode Javascript - Need to display invalid characters back to user

I'm looking for a solution that will solve the following problem but only have limited experience with Unicode.
Basically the user is able to type into a text field, however when they submit i want to display a list of the characters that WEREN"T GSM compliant. I.E everything that doesn't have a char code of 0-127.
However, it breaks severely when you bring emojis into the mix because if i char array it some emoji characters will get broken up and it will display the wrong reason why the validation failed.
I.E "๐Ÿ˜€".length = 2, it will get split into 2 characters and therefore when i tell the user why it failed they will get the wrong reason.
Any ideas on how i can solve this would be greatly appreciated.
EDIT: Can't use ES6 and need an array of the invalid characters
Supposing youโ€™re using a regex like this to find characters that arenโ€™t in the valid range:
/[^\0-\x7f]/
you can modify it to prefer to match UTF-16 surrogate pairs:
/[\ud800-\udbff][\udc00-\udfff]|[^\0-\x7f]/
On modern browsers, you can also just use the u flag to operate on Unicode codepoints directly:
/[^\0-\x7f]/u
This will still only get codepoints, though, and not grapheme clusters (important for combining characters, modern combined emoji, skin tone, and general correctness in all languages). Those are harder to deal with. When (if?) browser support appears, they will be less hard; until then, a dedicated package is your best bet.
var NON_GSM_CODEPOINT = /[\ud800-\udbff][\udc00-\udfff]|[^\0-\x7f]/;
var input = document.getElementById('input');
input.addEventListener('input', function () {
var match = this.value.match(NON_GSM_CODEPOINT);
this.setCustomValidity(match ? 'Invalid character: โ€œ' + match[0] + 'โ€' : '');
this.form.reportValidity();
});
<form>
<textarea id="input"></textarea>
</form>
You can use the spread operator (...) to break the characters into an array and then charCodeAt to get the value:
let str = `๐Ÿ˜€abc๐Ÿ˜€def๐Ÿ˜€ghi`;
let chars = [...str];
console.log(`All Chars: ${chars}`);
console.log('Bad Chars:',
chars.filter(v=>v.charCodeAt(0)>127)
);
Interesting! This is merely trial and error, but looks like converting the string to an array of chars strings using Array.from will allow you to index the characters correctly:
Array.from('๐Ÿ˜€').length
1
Array.from('๐Ÿ˜€abc').length
4
Array.from('๐Ÿ˜€abc')[0]
"๐Ÿ˜€"

Password validation regular expression special character

I want to use following code for password validation of at lest one character,number, upper case and lower case character
function fd3() {
alert("hii");
var v1 = document.getElementById("h3").value,
pass = /^([a-zA-Z0-9_##$%^&*]+$)/;
if(!pass.test(v1)) {
alert("Wrong Password");
}
}
Strictly speaking it does match your example of Abc#123.
Follow this link to see it matching Abc#123
However it doesn't do anything like what you think it does - it will match one or more character in that group - so simply "A" alone will match it.
You need something MUCH more complex like this:
^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[##$%^&+=]).*$
Debuggex Demo of the working example
I would also note that you did not have a requirement for a minimal number of characters so I did not include this in the regex. My list of special characters in this regex is also different from yours, but that can easily be changed by you if that is important.

Why do some valid regular expressions not work with the html5 pattern attribute?

See this fiddle: http://jsfiddle.net/5vTc7/
If you open the console, you can see that the regular expression in the pattern attribute ((?=^[0-9]*(\.[0-9]+)?$)(?=.*[1-9])) works as expected from JS, but when you enter anything in the input and try to submit, it fails.
In case there's something wrong with my regular expression, I'm simply trying to limit it to numbers greater than 0. I'd like to use the number input (i.e., <input type="number"/>), but I can't, because it doesn't allow you to format the values (e.g., it will display 0.00000001 as 1e-8, which is undesirable).
I am clueless here. Is there something I'm missing? Why doesn't this work?
When you use the pattern with anchors, as specified in The pattern attribute, it will fail with Javascript as well
var pattern = '^(?=^[0-9]*(\.[0-9]+)?$)(?=.*[1-9])$';
var reg = new RegExp(pattern);
console.log(reg.test('1.0')); // will fail
console.log(reg.test('0.0')); // will fail
See modified JSFiddle
If you want to limit the input to non-null numbers, you can use
\d*[1-9]\d*(?:\.\d*)?|\d+\.\d*[1-9]\d*
This pattern requires at least one non-null digit either before or after the decimal point.
See JSFiddle
You can try this pattern:
^(?:0+\.0*[1-9][0-9]*|0*[1-9][0-9]*(?:\.[0-9]+)?)$

Negating in /,?(([1-9]-[1-9])|([1-9]))/g

I am trying to match a string containing a mix of digits and hyphenated digits, like a crossword answer specification, for example 1,2-2 or 1-1,3,4,2-2
/,?(([1-9]-[1-9])|([1-9]))/g is what I've come up to match the string
value = value.replace(/,?(([1-9]-[1-9])|([1-9]))/g, '');
replaces ok, and I've checked it out in an online tester.
What I really need is to negate this, so I can use it on a keyup event, examine the contents of a textarea and remove characters that don't fit, so it only allows through characters as in the example.
I've tried ^ where expected, but this it's not doing what I expect, how should I negate the regex so I remove everything that doesn't match?
If there is a better way of doing this I'm open to suggestions too.
var value = 'hello,1,2,3,4-6,1-1,3,test,4,2-2';
var pattern = /,?(([1-9]-[1-9])|([1-9]))/g;
value.replace(pattern, ''); // "hello,test"
You can use String#match. With /g flag, it returns an array of all the matches, then you can use Array#join to join them.
The problem is that String#match returns null when there is no match, so you have to handle that case and use an empty array so that it can join:
(value.match(pattern) || []).join(''); // ",1,2,3,4-6,1-1,3,4,2-2"
Note: It may better to check them on onblur rather than onkeyup. Messing with the text that the user is currently typing will make it annoying. Better to wait for the user to finish typing.
Didn't test it in JS, but this should return the valid string beginning from the left and as long as valid values are encountered (note that I used \d - if you'd like 1-9 only, then use your brackets).
(?:\d(?:-\d)?,)*\d(?:-\d)?
E.g. matching this regular expression with the string "0-1,1,2,3,4-4,2,,1,3--4" will return "0-1,1,2,3,4-4,2" as the first match.

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