Forum Moderators: open
I'm wanting it to match the following formats
1234567890
123 456 7890
123-456-7890
(123) 456-7890
(123) 456 7890
Matches such as (123 456-7890 are acceptable as well
I've been able to get the first 3 of the above to match, its the presence of the ( )s that seems to be throwing me. Here is what I stopped with (or something similar). If anyone could supply me with a regex that would work and break down how it works I'd appreciate it. Thanks!
^\(?([0-9]{3})+\)?[\-\s]?([0-9]{3})+[\-\s]?([0-9]{4})+$
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
<title>Some Title</title></head>
<body>
<div>
<script type="text/javascript">//given that any phone number you need to validate
//will most likely come from a form input,
//all phone numbers will be strings
var phArr = [
'1234567890',
'123 456 7890',
'123-456-7890',
'(123) 456-7890',
'(123) 456 7890'
];var s = '';
var oRex = /^\(?([0-9]{3})+\)?[\-\s]?([0-9]{3})+[\-\s]?([0-9]{4})+$/;
for (var i = 0; i < phArr.length; i++) {
s += oRex.test(phArr[i]) + "<br>";
}document.write(s);
</script>
</div>
</body>
</html>
The following is 2 calls from a custom "class" defined in the same client.js file. d is defined as "document.theForm" and the values array is the various values from the form.
d.getElementById("phone").value = v.validate(v.isPhone(values[4]),"Please Enter a valid Phone Number","document.getElementById('phone').style.border = 'solid 1px #FF0000'; document.getElementById('phone').style.color = '#FF0000'");
Here are the 2 functions being called from the "v" object. The check for regex is is the "isPhone" function. I'm pretty certain I've got it right. Please note that returning the value as an array instead of a string equates to false and trips the validate function (I've included it if that doesn't make sense).
this.validate = function(val,err,doThis) {
if (val.constructor.toString().indexOf("Array") == -1) {
return val;
} else {
if (!error) {
if ((val.length > 1) && (val[1] != "")) { alert(val[1]); } else { alert(err); }
error = true;
}
if (doThis != "undefined") {
if (val.length > 2) { eval(val[2]); } else { eval(doThis); }
}
return val[0];
}
}
this.isPhone = function(phone) {
var filter = /^\(?([0-9]{3})+\)?[\-\s]?([0-9]{3})+[\-\s]?([0-9]{4})+$/;
if (!filter.test(phone)) {
return [phone]; //fail
}
return phone;
}
Thanks for the help :-)
[edited by: Randomgnome at 1:53 am (utc) on May 13, 2009]
The check for regex is is the "isPhone" function. I'm pretty certain I've got it right. Please note that returning the value as an array ? instead of a string equates to false and trips the validate function (I've included it if that doesn't make sense).
this.isPhone = function(phone) {
var filter = /^\(?([0-9]{3})+\)?[\-\s]?([0-9]{3})+[\-\s]?([0-9]{4})+$/;
if (!filter.test(phone)) {
return [phone]; //fail, of course, this is an incorrect declaration of an array
}
return phone;
}
Yeah, that doesn't make any sense to me, as to why you are trying to return that way. Usually there is really no need to return the actual phone number, and the isPhone function could just be like:
this.isPhone = function(phone) {
var filter = /^\(?([0-9]{3})+\)?[\-\s]?([0-9]{3})+[\-\s]?([0-9]{4})+$/;
return filter.test(phone); //return true or false
}
Also, a comment or two I had on your validate function:
this.validate = function(val,err,doThis) {
if (val.constructor.toString().indexOf("Array") == -1) {
//the above condition equates exactly to:
// if (!(val instanceof Array)){ //if val is not an Array
return val;
}
And apparently you like to use eval and have not heard to stay away from it. There is always a better way, you will find anonymous functions very useful in this regards.
The code could be entirely reworked to be more like:
d.getElementById("phone").value = v.validate(
v.isPhone(values[4]), //true or false value being returned here
"Please Enter a valid Phone Number",
function () { //rather than evaluating a string (eval is evil), pass in an anonymous function
var el = document.getElementById('phone');
el.style.color = '#FF0000';
//Safari doesn't like single border declarations such as 'solid 1px #FF0000',
//at least not in javascript and I've had issues with it in past,
//so break it down to the individual properties
el.style.borderWidth = '1px';
el.style.borderStyle = 'solid';
el.style.borderColor = '#FF0000';
}
);this.validate = function(val,err,doThis) {
if (!(val instanceof Array)){ //if val is not an Array
return val;
} else {
if (!error) {
if ((val.length > 1) && (val!= "")) {
alert(val[1]);
} else {
alert(err);
}
error = true;
}
if (doThis != "undefined") {
if (val.length > 2 && typeof val[2] == 'function') {
val[2](); //place an anonymous function in val[2] from now on, don't use eval
} else if (typeof doThis == 'function') {
doThis();
}
}
return val[0];
}
}this.isPhone = function(phone) {
var filter = /^\(?([0-9]{3})+\)?[\-\s]?([0-9]{3})+[\-\s]?([0-9]{4})+$/;
return filter.test(phone);
}
Anyhow, the above is untested and just meant to show possible improvements to those parts of the overall code. And actually, I don't understand what the first else block's first if statement's first if statement is for in the validate function: (if ((val.length > 1) && (val!= "")) {
alert(val[1]);
}. ), but, no matter to me. If you still have trouble/questions, come on back, and by the way.. welcome to webmasterworld!
I was actually going to add another function to the "class" which accepts a reference to the form field, d.SomeField, as an argument. That function would change out the borders and font color. Assuming the received value equates to false it calls that function and passes the reference, which was in turn passed to it. The phone value is returned because most of the validation functions (isPhone, for example) also cleans the string of white space and various undesirable characters (sql injection concerns mostly). As our form submits into a database and a CRM I need to ensure the strings are as clean as possiable. I've never had an issue declaring an array as someVar = [val1,val2,val3,...]; but if it gives me issues I can switch it over to return new Array(phone);
The odd && condition is from a previous iteration of this project, which I just missed . Thanks for pointing that out for me.
I should have a chancse to make these changes and test them out in a few hours. If I have any further difficulities with the regex I'll let you know. I did have a few questions however:
The test that I'm doing in the isPhone function is correct? Will it return an array of matches or just a Boolean true?
Can you explain to me when I would use the pares ( and ) in a regex? I'm learning regex off online tutorials and forum discussions and there just isn't a whole lot of good info out there. From what I can tell using ^[0-9a-zA-Z]+$ would require any alphanumeric character to appear at least once and accept it up to an infinite number of characters, matching basically any alphanumeric string. What would the difference between that and ^([0-9a-zA-Z])+$ be?
edit: hckd on fniks dinn wrk fer mee!
[edited by: Randomgnome at 6:10 pm (utc) on May 13, 2009]
I did have a few questions however:
The test that I'm doing in the isPhone function is correct? Will it return an array of matches or just a Boolean true?
As for being correct, it appears so, but there are a few flaws. There is not any checking that if one '(' is present a ')' should be present also and in proper place, ditto the '-' characters. It does get a bit complicated when supporting 5 or more different formats, which is a fine thing to do, but may desire more thorough checking even yet.
var filter = /^\(?([0-9]{3})+\)?[\-\s]?([0-9]{3})+[\-\s]?([0-9]{4})+$/;
The above won't precisely match whether there is one '(' there should be a ')' and etc.., also, instead of using [0-9] use \d
var filter = /^\d{10}$¦^\d{3}\s\d{3}\s\d{4}$¦^\d{3}-\d{3}-\d{4}$¦^\(\d{3}\)\s\d{3}(-¦\s)\d{4}$/;
The above is one long-form RegExp that will precisely match the following 5 formats:
'1234567890'
'123 456 7890'
'123-456-7890'
'(123) 456-7890'
'(123) 456 7890'
(Just break the mRex apart at each 'or' ¦ conditional for each format, with the last check checking the two final formats using (-¦\s), there may be a shorter way yet, but is sufficient. It all depends of course on your own requirements. Also note this forum wrecks the or conditionals ¦ and they may need to be replaced before usage.)
Can you explain to me when I would use the pares ( and ) in a regex?
<script type="text/javascript">var str = 'Astringoftext';
var strM = str.match(/^[a-zA-Z0-9]+$/);
var strM2 = str.match(/^([a-zA-Z0-9]+)$/);alert(strM + "\n" + strM2);
//note that strM2 returns two items,
//the first one being the entire match it's self as the first item in
//the array returned. Second item in the array in this case is
//the captured part via the parens (). A better example:var str = 'A string of text';
var strM = str.match(/^([a-z]+)\s([a-z]+)\s([a-z]+)\s([a-z]+)$/i);
//because of the parens, each set of characters
//contained in the parens above will be captured by the match method.
//strM basically verifies there are exactly 4 words
//seperated by a space and captures- () -each grouping of characters
if (strM !== null) {
//note there will actually be 5 items returned in the array of matches.
//strM will return the entire match as the first item in array of matches
//and each individual match as the rest of the array's items
alert(strM + "\n\n" + strM[0] + "\n\n" + strM[4]);
}/*****
or even better, we only want to capture the fourth word, so only use the parens on it:
*****/
var str = 'A string of text';var strM = str.match(/^[a-z]+\s[a-z]+\s[a-z]+\s([a-z]+)$/i); //just capturing ([a-z]+) the fourth character grouping
//because of the parens, each set of characters
//contained in the parens above will be captured by the match method.
//strM basically verifies there are exactly 4 words
//seperated by a space and captures- () -THE LAST WORD
if (strM !== null) {
//note there will actually be 2 items returned in the array of matches.
//strM will return the entire match as the first item in array of matches
//and each individual captured () match as the rest of the array's items
alert(strM + "\n\n" + strM[0] + "\n\n" + strM[1]);
}
</script>
d.getElementById("phone").value = v.validate(
And I must confess, I know my earlier post doesn't support the above very well actually, as you are trying to assign new value to the input. I don't see why you would want to do that anyways... , should just notify the user to fix their entry. My earlier example is actually more intended to be something more like:
var someVar = v.validate( //yadda yadda yadda... etc...
if (someVar) {// or: return someVar; or: do some other stuff....