 
Figure A: We'll re-use the Web page we created for our July issue to illustrate using regular expressions for data validation.
![[ Figure A ]](mit9993a.gif) 
 
Regular expressions: a brief introduction
A JavaScript regular expression is created by surrounding a text pattern with forward slashes. As a simple example, suppose you wanted to find if the word top was contained in a text string. We could use a regular expression that looked like this:
var myExp = /top/
var found = myExp.test("Stop at the 
=>big top")
But suppose that what we really wanted to find was the actual word top, rather than just a part of the word Stop? We can modify our regular expression using metacharacters that can further define the pattern. For example,
var myExp = /\btop/ 
Some metacharacters also determine how many times a matching character or symbol should occur. For example, to match a number with three digits, the pattern would look like this, where the \d stands for a single digit:
var myExp = /\d{3}/
Table A: Regular expression metacharacters
| Character | Matches | 
|---|---|
| \b | Word boundary | 
| \B | Word nonboundary | 
| \d | Numeral 0 through 9 | 
| \D | Non-numeral | 
| \s | Single white space | 
| \S | Single nonwhite space | 
| \w | Letter, numeral or underscore | 
| \W | Not letter, numeral or underscore | 
| . | Any character except newline | 
| [...] | Character set | 
| [^...] | Negated character set | 
| * | Last character occurring zero or more times | 
| ? | Last character occurring zero or one time | 
| + | Last character occurring one or more times | 
| {n} | Last character occurring exactly n times | 
| {n,} | Last character occurring n or more times | 
| {n,m} | Last character occurring at least n, at most m times | 
| ^ | Pattern occurring at the beginning of the string | 
| $ | Character occurring at the end of the string | 
| g | All occurrences of the pattern; that is, (g)lobal | 
| i | Case (i)nsensitive occurrences of the pattern | 
| | | OR operator | 
| Note: To include a character in a pattern that could be interpreted as a metacharacter, use the escape symbol (\) in front of the character. For example, the regular expression /\d{3}\.\d{2} specifies a pattern of three digits, followed by a period, followed by two digits. We've used the escape symbol in front of the period (.) because we want to represent an actual period, not the metacharacter (.). | 
Regular expressions for data validation
With this very basic introduction in mind, let's look at some examples of regular expressions that we can use for validating and reformatting user-entered data. We'll then use the expressions to rewrite the validation functions we developed in our July issue, and add two new functions to our repertoire as well.
Null and blank strings
With regular expressions, we can rewrite the notBlank and notNull functions we used in the July article to more specifically address the needs of our data. For example, if we require only that the text box not be left blank, we can use the regular expression:
var charexp = /./
var letterexp = /[a-z]/i
The pattern contains the character set of any letter from a to z, so any letter would serve as a match. The i at the end of the expression specifies that either an upper-case or lower-case letter is acceptable.
Member number
Our membership number is required to have three digits (0-999) and we don't want any other extraneous characters before or after. The regular expression to represent this pattern would be:
var memberexp = /^\d{3}$/
ZIP code
This one is just a little bit trickier, because we have the option of either a five-digit or a nine-digit ZIP code. Here's the regular expression we can use:
var zipexp = /^\d{5}$|^\d{5}[\-
=>\s]?\d{4}$/
Placing the dash and the space in brackets ([]) indicates that they form a character set, either of which is a match. Note that the dash needs to have a backward slash (escape character) in front of it so that the expression knows that it's actually a dash and not a metacharacter. The question mark (?), indicating zero or one occurrences, is placed immediately after the character(s) it modifies (in our case, the character set of dash or space).
Phone
Validating a phone number is simpler, especially if we simplify the problem by first stripping off any extraneous characters. We'll get to reformatting strings in a minute. Here's the regular expression:
var phonexp =  /^\d{10}$/
Email addresses
Now we get a bit more complicated, since email can take many different forms. Here's the expression:
var emailexp = /^[a-z][a-z_0-9\.]+@[a-z_
=>0-9\.]+\.[a-z]{3}$/i
Pledge amount
Checking to be sure that we have a valid pledge amount isn't as complicated, since we can again use our formatting functions to limit the string we're looking at. Assuming that we'll have a string comprised only of digits and a possible decimal point, our expression looks like this:
var pledgexp = /^\d*$|^\d*\.\d{2}$/
New reformatting functions
In our July issue, we wrote the code for the functions stripChars and stripNonDigits for reformatting a text string before we tried to validate it. Now that we have a basic understanding of regular expressions, we can use the String object's replace method to rewrite both functions with just one line of code. The replace method requires two parameters: a regular expression used for searching a string for a match and a string to replace the match that was found. When called, it replaces the first occurrence of the search string with the replacement string, and returns the new string. To replace all occurrences of the string, you need to add the g metacharacter to the regular expression.
A revised stripChars function
Recall that the function stripChars accepts as parameters the characters to be removed from a text string, and the original string. We can instead pass a regular expression to find the characters we want to remove. For example, to strip the dollar sign from our pledge amount we could call stripChars,passing the regular expression and the text box string, with the statement:
newpledge = stripChars(/\$/,
=>form.pledge.value)
This would mean that stripChars now requires just one line of code:
function stripChars(pattern, str) {
	return str.replace(pattern,")
}
The function accepts the regular expression into pattern, and the string from the text box into str. Using the replace method, it replaces any occurrences of the pattern found in the string (in this case, a dollar sign) with a null string (that is, with nothing), and returns the resulting string.
A revised stripNonDigits function
Rewriting the stripNonDigits function is just as simple. In our example, we use stripNonDigits to strip any extraneous characters from the phone number that the user has entered. Our call to the function only passes the string we want stripped of any non-digits:
newphone = stripNonDigits
=>(form.phone.value)
The function replaces all occurrences of any character that's not 0-9 with a null string using the negated character set ([^0-9]), and the global metacharacter (g):
function stripNonDigits(str) {
	return str.replace(/[^0-9]/g,")
}
A generic validation function
Now that we've defined regular expressions for each of our text box values, we can create a generic validation function that's passed a text box field and the regular expression we created to validate it. To actually test for a match between the regular expression and a string, we can use the Regular Expression object's test method. Once we've passed the regular expression into a parameter (let's call it pattern) and the string we want to test into a second parameter (say, str) our validation function consists of one statement:
function isValid(pattern, str) {
	return pattern.test(str)
}
where the test function will check to see if the string it was passed matches the pattern it was passed.
Putting it all together (again)
The full code for our regular expression validation script is found in Listing A. For completeness, the HTML code for the page is in Listing B.
Listing A: Script for data validation with regular expressions
<SCRIPT>
<!--
	
var charexp = /./
var letterexp = /[a-z]/i
var phonexp =  /^\d{10}$/
var memberexp = /^\d{3}$/
var zipexp = /^\d{5}$|^\d{5}[\-\s]?\d{4}$/
var emailexp = /^[a-z][a-z_0-9\.]+@[a-z_0-9\.]+\.[a-z]{3}$/i
var pledgexp = /^\d*$|^\d*\.\d{2}$/
function isValid(pattern, str) {
	return pattern.test(str)
}
function hasLetter(str) {
	return letterexp.test(str)
}
function hasChar(str) {
	return charexp.test(str)
}
function stripChars(pattern, str) {
	return str.replace(pattern,")
}
function stripNonDigits(str) {
	return str.replace(/[^0-9]/g,")
}
function checkform(form) {
	//Check the first name text box for an entry
	if  (!hasLetter(form.firstname.value)) {
		alert("Invalid first name")
		form.firstname.focus()
		return false
	}
	//Check the last name text box for an entry
	if (!hasLetter(form.lastname.value)) {
		alert("Invalid last name")
		form.lastname.focus()
		return false
	}
	//Check that the member number entry is valid
	if (!isValid(memberexp,form.membernum.value)) {
		alert("Invalid member number")
		form.membernum.focus()
		return false
	}
	//Check that the ZIP code entry is valid.
	if (!isValid(zipexp,form.zip.value)) {
		alert("Invalid ZIP code")
		form.zip.focus()
		return false
	}
	//Check that the email entry is valid
	if (!isValid(emailexp,form.email.value)) {
		alert("Invalid email")
		form.email.focus()
		return false
	}
	
	//Check that the phone entry is valid by first 
	//stripping off all nondigits.
	newphone = "
	if (hasChar(form.phone.value)) {
		newphone = stripNonDigits(form.phone.value)
		notvalid = !isValid(phonexp,newphone)
	}
	if (newphone == " || notvalid) {
	alert("Invalid phone number - include area code")
		form.phone.focus()
		return false
	}
	//Check that the phone entry is valid by first 
	//stripping off all any dollar sign using stripChars.
	newpledge = "
	if (hasChar(form.pledge.value)) {
		newpledge = stripChars(/\$/,form.pledge.value)
		notvalid = !isValid(pledgexp,newpledge)
	}
	if (newpledge == " || notvalid) {
		alert("Please enter a valid dollar amount")
		form.pledge.focus()
		return false
	}
	
	alert("Data valid")
}
//-->
</SCRIPT>
Listing the regular expressions
The first thing you'll notice about our new script is that the code is a lot shorter. In fact, we've reduced one level of function calls.
Next, notice that we've placed all of our regular expressions at the head of our script. We did this to make them easy to see, and also easy to change if you want to revise them later. Let's now take a look at the checkform function that's called by the Submit button, and which runs the whole show.
Validating name fields with hasLetter
The first thing checkform does is call the hasLetter function, passing the strings in both the first name and last name text boxes. hasLetter checks that each string contains at least one alphabetical character. For each text box that checkform tests, just as we did in our July issue, if the string comes back as not valid, the user is given a message, focus is returned to the text box, and the function returns a false to the Submit button call.
Validating fields with isValid
After checking the name fields, checkform calls the isValid function for the member number, email, and ZIP code entries, passing up their regular expressions along with the strings in each of the text boxes. Refer back to the list of regular expressions at the top of the listing to see what's being passed to isValid each time.
Reformatting phone and pledge fields
Finally, checkform calls stripNonDigits to remove extraneous characters from the phone entry, and calls stripChars to remove the dollar sign ($) from a pledge amount. The logic here was a little trickier. For both the phone and the pledge entries, we start by setting a string value to null. We then check that the fields contain at least one character by calling the function hasChar. If they do, we assign the reformatted string to the string variable we had originally set to null. Then, we call isValid with the reformatted string. If the string is still null (that is, the field must have been null because the string was never reset) or if isValid found that the string wasn't valid, we alert the user and return false to the call.
Listing B: HTML code for our data validation page
<HTML>
<HEAD>
<STYLE>
P {font-size:18}
H1 {text-align:center}
b {text-align:center;font-size:20}
TEXTAREA {font-weight:900}
</STYLE>
<! Script goes here
</HEAD>
<BODY>
<P style = "text-align:center;font-size:24">
	Pinebarren Public Radio
<P style = "text-align:center;font-size:20;" >
	Pledge Form
<FORM>
<TABLE border="0" width="450" cols = 4>
<TR>
<TD><i>First Name</i></TD>
<TD><i>Last Name</i></TD>
<TD><i>Member#</i></TD>
</TR>
<TR>
<TD><INPUT type="text" name="firstname" size="20"></TD>
<TD><INPUT type="text" name="lastname" size="20"> </TD>
<TD><INPUT type="text" name="membernum" size="15"></TD>
</TR>
<TR>
<TD><I>Address</I></TD>
<TD><I>City</I></TD>
<TD><I>State</I></TD>
<TD><I>ZIP Code</I></TD>
</TR>
<TR>
<TD><INPUT type="text" name="address" size="20"></TD>
<TD><INPUT type="text" name="city" size="20"></TD>
<TD><INPUT type="text" name="state" size="3" ></TD>
<TD><INPUT type="text" name="zip" size="12" ></TD>
</TR>
<TR>
<TD><i>Email</i></TD>
<TD><i>Phone</i></TD>
</TR>
<TR>
<TD><INPUT type="text" name="email" size="20"></TD>
<TD><INPUT type="text" name="phone" size="20"></TD>
</TR>
</TABLE>
<BR>
<BR>
<TABLE>
<TR><TD><i>Pledge Amount</i> </TD>
<TD> <input type="text" name="pledge" size="20"></TD>
</TR>
</TABLE>
<BR>
<INPUT type = "button"  value = "Submit" 
onclick = "return checkform(this.form)">
<INPUT type = "reset"  value = "Reset">
</FORM>
</CENTER>
</BODY>
</HTML>
Conclusion
In this article, we gave you a very brief overview of regular expressions, and showed you how they could be used to implement data validation functions. You should know, however, that we've only barely provided a glimpse into both the power and the complexity of regular expressions, and the many ways they can be put to use. For more information, pick up Jeffrey Friedl's book, Mastering Regular Expressions: Powerful Techniques for Perl and Other Tools.
Copyright © 1999, ZD 
      Inc. All rights reserved. ZD Journals and the ZD Journals logo are trademarks of ZD 
      Inc. Reproduction in whole or in part in any form or medium without 
      express written permission of ZD Inc. is prohibited. All other product 
      names and logos are trademarks or registered trademarks of their 
      respective owners.