Solved

Help with email address validation checker - allow two periods but ensure text exists after last period

Posted on 2008-10-08
15
505 Views
Last Modified: 2010-04-21
I am new to javascript.  I need to edit my email validation function to allow two dots but make sure that the last dot still has something after it.

The code I am working with is given below FIRST,  the second code snippet function is an email validator i found on the web.  It allows for two periods, and makes sure that there is something after the final "."  But since I'm new to js I'm having trouble understanding why it works.  

Can someone please explain to me?  Is -1 the FIRST position in the field or is 0 the first position?  Which part of the second snippet I pasted allows for two dots as well as not allowing it to pass if there is nothing after the final .

My code doesn't return "joe.joe@joe." as invalid
but the one i found on the web does.


function checkForValidEmailAddress(emailAddressField) 

{

	var emailAddress = emailAddressField.value;

	

	// Do not throw an error if the field is blank.

	if ("" == emailAddress) 

	{

		return true;

	}

	

	var at = "@";

	var dot = ".";

	var positionOfAtSymbol = emailAddress.indexOf(at);

	var lengthOfAddress = emailAddress.length;
 

	// Check to see if an "@" character exists.

	// If it does exist, it should not be as 

	// the first or last character of the address.

	if (emailAddress.indexOf(at) == -1 

		|| emailAddress.indexOf(at) == 0 

		|| emailAddress.indexOf(at) == lengthOfAddress - 1)

	{

		emailAddressField.select();

		emailAddressField.focus();

		return false;

	}
 

	// Check to see if an "." character exists.

	// If it does exist, it should not exist as 

	// the first or last character of the address.

	if (emailAddress.indexOf(dot) == -1 

		|| emailAddress.indexOf(dot) == 0 

		|| emailAddress.indexOf(dot) == lengthOfAddress - 1 )

	{

		emailAddressField.select();

		emailAddressField.focus();

		return false;

	}
 

	// Make sure that there is a second "." character.

	if (emailAddress.indexOf(at,(positionOfAtSymbol + 1)) != -1)

	{

		emailAddressField.select();

		emailAddressField.focus();

		return false;

	}
 

	// Make sure that a "." character does not immediately

	// preceed or follow the "@" character.

	if (emailAddress.substring(positionOfAtSymbol - 1, positionOfAtSymbol) == dot 

		|| emailAddress.substring(positionOfAtSymbol + 1, positionOfAtSymbol + 2) == dot)

	{

		emailAddressField.select();

		emailAddressField.focus();

		return false;

	}
 

	// Make sure there exists at least one "." 

	// character after the "@" character.

	if (emailAddress.indexOf(dot,(positionOfAtSymbol + 2)) == -1)

	{

		emailAddressField.select();

		emailAddressField.focus();

		return false;

	}
 

	// Make sure there is no whitespace within the address.

	if (emailAddress.indexOf(" ") != -1)

	{

		emailAddressField.select();

		emailAddressField.focus();

		return false;

	}
 

	return true;				

}
 
 

<script language = "Javascript">

function echeck(str) {
 

		var at="@"

		var dot="."

		var lat=str.indexOf(at)

		var lstr=str.length

		var ldot=str.indexOf(dot)

		if (str.indexOf(at)==-1){

		   alert("Invalid E-mail ID")

		   return false

		}
 

		if (str.indexOf(at)==-1 || str.indexOf(at)==0 || str.indexOf(at)==lstr){

		   alert("Invalid E-mail ID")

		   return false

		}
 

		if (str.indexOf(dot)==-1 || str.indexOf(dot)==0 || str.indexOf(dot)==lstr){

		    alert("Invalid E-mail ID")

		    return false

		}
 

		 if (str.indexOf(at,(lat+1))!=-1){

		    alert("Invalid E-mail ID")

		    return false

		 }
 

		 if (str.substring(lat-1,lat)==dot || str.substring(lat+1,lat+2)==dot){

		    alert("Invalid E-mail ID")

		    return false

		 }
 

		 if (str.indexOf(dot,(lat+2))==-1){

		    alert("Invalid E-mail ID")

		    return false

		 }

		

		 if (str.indexOf(" ")!=-1){

		    alert("Invalid E-mail ID")

		    return false

		 }
 

 		 return true					

	}
 

function ValidateForm(){

	var emailID=document.frmSample.txtEmail

	

	if ((emailID.value==null)||(emailID.value=="")){

		alert("Please Enter your Email ID")

		emailID.focus()

		return false

	}

	if (echeck(emailID.value)==false){

		emailID.value=""

		emailID.focus()

		return false

	}

	return true

 }

Open in new window

0
Comment
Question by:Bishork
  • 9
  • 6
15 Comments
 
LVL 3

Expert Comment

by:robacarp
Comment Utility
To answer your questions:

"Is -1 the FIRST position or is 0 the first position"

> Zero.  haystack.indexOf(needle) returns -1 when needle is not found in haystack.  Otherwise it returns the position of it in the string.  

"Which part of the second snippet I pasted allows for two dots as well as not allowing it to pass if there is nothing after the final ."

Um...quite a bit of it.  See attached snippet with my comments.
function echeck(str) {

 

                var at="@"

                var dot="."

                var lat=str.indexOf(at)

                var lstr=str.length

                var ldot=str.indexOf(dot)

//checks to see if there is no @ in the email.

                if (str.indexOf(at)==-1){

                   alert("Invalid E-mail ID")

                   return false

                }

 

//checks to see that the @ is: present, not at the zero position (the beginning), and not at the end position (lstr)

                if (str.indexOf(at)==-1 || str.indexOf(at)==0 || str.indexOf(at)==lstr){

                   alert("Invalid E-mail ID")

                   return false

                }
 

//checks to see if the . is present, not at the zero position, and not at the end position

                if (str.indexOf(dot)==-1 || str.indexOf(dot)==0 || str.indexOf(dot)==lstr){

                    alert("Invalid E-mail ID")

                    return false

                }
 

//checks to see that there are not two @ signs

                 if (str.indexOf(at,(lat+1))!=-1){

                    alert("Invalid E-mail ID")

                    return false

                 }

 

//checks to make sure that the . is not directly before or directly after the @

                 if (str.substring(lat-1,lat)==dot || str.substring(lat+1,lat+2)==dot){

                    alert("Invalid E-mail ID")

                    return false

                 }

 

//checks to make sure that there are at least two characters after the @ and before the .

                 if (str.indexOf(dot,(lat+2))==-1){

                    alert("Invalid E-mail ID")

                    return false

                 }

                
 

//checks to make sure that there are no spaces

                 if (str.indexOf(" ")!=-1){

                    alert("Invalid E-mail ID")

                    return false

                 }

 

                 return true                                    

        }

Open in new window

0
 
LVL 3

Expert Comment

by:robacarp
Comment Utility
Let me also mention that, while you can weed out some basic flaws in entry, you cannot validate an email address without sending a verification email to the address to make them click on a unique link back to your server.

I'd also like to post what I would use....you are welcome to use it.  Test it out first and see if it will do what you want by pasting the code section below into a webpage.

It uses a method of string processing called a Regular Expression.  Regular Expressions are much faster and more flexible than a series of substring and indexOf calls and are available in almost every programming language.  They can be a pain to get used to, but once you get them down you will have real power in your hands.  Check out this website for more information: http://www.regular-expressions.info/
function validateEmail(email){

   emailReg = /^[0-9a-z.]{2,}[0-9a-z]{2,}@[0-9a-z]{2,}[0-9a-z.]{2,}$/i;

   if (re.exec(email).index<0){

//the email address didn't validate

      return false;

   }

   return true;

}
 

for (;;){

if (e=prompt("lets test an email....(blank to quit)",'')){

   alert('valid');

} else {

   alert('invalid');

}

if (e=='') break;

}

Open in new window

0
 

Author Comment

by:Bishork
Comment Utility
roba - first of all thanks for responding - i have a couple more quick questions

(dot,(lat+2))

how is that two characters after the @ and before the .?

is

exec matches to see if what you are looking for is in a string right, what does the "re." do

why .index and then why .index<0?  how are regular expressions more useful?  ill read the website too but thought i'd ask if it doesnt say on the site.

for (;;){ <-- what does ;; mean to the for loop?

i want to use yours but i need to understand it well enough before i can use it.  can you also help me just add to mine what i'd need to fix it so it wont allow d.dd@ddd.  

also, if i pass an < > " ' & symbol in my email field, the xml breaks.  so i have a separate error code for that.  it simply says "please remove & " ' or < > before submitting your email address"

it seems like a crappy way to make someone remove an invalid character and id like to know if there is a superior way to do this


sorry for all the Q's and thanks for the help, im trying to learn this stuff quick.  
0
 
LVL 3

Expert Comment

by:robacarp
Comment Utility
Questions & Answers:
> (dot,(lat+2)) how is that two characters after the @ and before the .?
It is not.  str.indexOf(dot,(lat+2) is.  There is a big difference.

indexOf is a function of a string (the haystack).  It can be used with one argument or two.  Arguments are the things in between the () and separated by commas.  When using indexOf, the first argument is what you are looking for (the needle).  If you provide the second argument, it is a spot in the string to start from.  In this case, lat is the location of the @ symbol in the string.  that line is saying, add 2 to the location of the @ symbol and start searching for a . from there.  If it exists, indexOf will be equal to something other (and greater than) -1.

> why .index and then why .index<0

The javascript regular expression function exec() returns (gives back) some properties...one of them is called 'index' and it works similar to the indexOf function.  When the index property is <0, the pattern didn't match.

> how are regular expressions more useful?

With practice, regular expressions can help you look for patterns in a string that would be incredibly difficult to program otherwise.  It is hard to come up with an example off the top of my head.  The fact that regular expressions are included in nearly every modern programming language is testament to their usefulness, even despite their steep learning curve.

> for(;;){ <---- what does ;; mean to the for loop?

the standard for loop syntax is:
for (begin_statement; test_statement; end_statement){
//do stuff
}

where when the loop first starts, it executes begin_statement.  Each time it finishes a pass through the loop, it will run end_statement.  Finally, just before it starts all of its passes, it checks to make sure test_statement is still true.

By putting nothing into those statements, the loop will essentially run forever.  It is essentially the same as:

while (true) {
//do stuff
}

>i want to use yours but i need to understand it well enough before i can use it.
A good plan.

>also, if i pass an < > " ' & symbol in my email field, the xml breaks.  so i have a separate error code for that.  it simply says "please remove
>>& " ' or < > before submitting your email address"

Most of those are invalid characters in an email address anyways.  Though I think an email address like bob&bob@yourname.com is valid.  Either way, I would make one error message that says: "The email address you have entered appears invalid.  Please remove any of these characters & " ' < >".

Nevertheless, I have augmented your code (highlited by *****) to check for the . at the end.

Btw, good use of longer variable names.  Using names like lat and ldot is easily understood by the writer but not anyone that reads it.  Your formatting is good as well.  Keep up with that....it'll earn respect in the programming community.
function checkForValidEmailAddress(emailAddressField) 

{

        var emailAddress = emailAddressField.value;

        

        // Do not throw an error if the field is blank.

        if ("" == emailAddress) 

        {

                return true;

        }

        

        var at = "@";

        var dot = ".";

        var positionOfAtSymbol = emailAddress.indexOf(at);

        var lengthOfAddress = emailAddress.length;

 

        // Check to see if an "@" character exists.

        // If it does exist, it should not be as 

        // the first or last character of the address.

        if (emailAddress.indexOf(at) == -1 

                || emailAddress.indexOf(at) == 0 

                || emailAddress.indexOf(at) == lengthOfAddress - 1)

        {

                emailAddressField.select();

                emailAddressField.focus();

                return false;

        }

 

        // Check to see if an "." character exists.

        // If it does exist, it should not exist as 

        // the first or last character of the address.

/*********************

you are close....

you had :

emailAddress.indexOf(dot) == lengthOfAddress -1;
 

which makes sure there isn't a dot in the place before the end.

***********************/

        if (emailAddress.indexOf(dot) == -1 

                || emailAddress.indexOf(dot) == 0 

                || emailAddress.indexOf(dot) == lengthOfAddress )

        {

                emailAddressField.select();

                emailAddressField.focus();

                return false;

        }

 

        // Make sure that there is a second "." character.

        if (emailAddress.indexOf(at,(positionOfAtSymbol + 1)) != -1)

        {

                emailAddressField.select();

                emailAddressField.focus();

                return false;

        }

 

        // Make sure that a "." character does not immediately

        // preceed or follow the "@" character.

        if (emailAddress.substring(positionOfAtSymbol - 1, positionOfAtSymbol) == dot 

                || emailAddress.substring(positionOfAtSymbol + 1, positionOfAtSymbol + 2) == dot)

        {

                emailAddressField.select();

                emailAddressField.focus();

                return false;

        }

 

        // Make sure there exists at least one "." 

        // character after the "@" character.

        if (emailAddress.indexOf(dot,(positionOfAtSymbol + 2)) == -1)

        {

                emailAddressField.select();

                emailAddressField.focus();

                return false;

        }

 

        // Make sure there is no whitespace within the address.

        if (emailAddress.indexOf(" ") != -1)

        {

                emailAddressField.select();

                emailAddressField.focus();

                return false;

        }

 

        return true;                            

}

Open in new window

0
 

Author Comment

by:Bishork
Comment Utility
Hi roba,

thanks for all the explainations. I'm going to read them right now.  

I've specified more of what I want to require -

Require at least one @
Legal in domain: -, A-Z, a-z, 0-9,  
Require at least on character between the @ and the following period (this is the domain

section).
Require 1-2 periods extensions after domain (support cnn.co.il as well as cnn.com)
Require 2 characters after the final .
Support two periods after the @ symbol, but they cannot be in a row.
Require at least 2 characters after the final . after the @ symbol
Do not allow whitespace  

Can you help me put together this js?  If your above explaination and code does this then nevermind, I just thought I would post this before I forget:)  thanks for all your help
0
 

Author Comment

by:Bishork
Comment Utility
i also don't want two periods after the @ symbol to be in a row -

Ok this is the final version of what I am trying to accomplish, I've been writing and rewriting my requirements so I don't have to go back and change my code after I think of something.  This is good practice too right?

Email addresses are made up of (localportion@domain)

Legal in local portion (portion prior to @):

A-Z
a-z
0-9
.
- (hyphen)
_ (underscore)
*Disallow anything else*

Required to be at least 1 character long


@ symbol is required to split up the local portion and domain portion


Legal in domain (portion after @ before the .):
- (hyphen)
A-Z
a-z
0-9
.
*Disallow anything else*

Required to be at least 4 character long

Requires at least one .

Supports two periods after the @ symbol (example:  x@xxx.xx.xx)
Requires at least 2 characters after the final . (examples: x@x.xx)
Support two periods.
0
 
LVL 3

Expert Comment

by:robacarp
Comment Utility
This should work.

Btw, if you are looking for a good tool to help with learning regexs, check out http://reggyapp.com/ or if you are on a PC, http://www.weitz.de/regex-coach/
function validateEmail(email){

   emailReg = /^[a-z0-9-][a-z0-9._-]+@[a-z0-9.-]{4,}\.[a-z0-9]{2,}$/i;

   if (re.exec(email).index<0){

//the email address didn't validate

      return false;

   }

   return true;

}

Open in new window

0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 

Author Comment

by:Bishork
Comment Utility
Thanks a lot for all your help, these will be my final questions -

So your function takes an email argument, whatever is in the field, the string of allowable characters format is what's in the first set of brackets or the second set of brackets before the @ sign?  a-z is twice before the @ sign but there is no _ or . in the first set.  I guess I'm asking you to break it down for me so I know what each bracket is saying, why do we need two brackets before the @, the + sign is saying allow all these before an @ right, then the next bracket is saying allow alpha numeric, periods, and dashes but there has to be a minimum of 4 characters, then we separate that part with an escaped dot \. and say the next portion can only have a-z and 0-9 and has to be a minimum of two.  Right?  But what is stopping us from putting in two periods right next to eachother after the @ symbol, a string of 4 periods for example?

 Also to start the list of allowable characters we begin with with a ^ and escape it with a / so always start with /^ and end with $/i;?  
      
Also, re.exec wouldn't know to check what we pass in as email with emailReg so shouldnt it  be  (emailReg.exec(email).index<0) rather than re?

lastly, if the exec returns an index property of <0, you said the pattern didn't match, so that means it didn't meet the format given our stipulations and we kick it out right.  

0
 
LVL 3

Accepted Solution

by:
robacarp earned 500 total points
Comment Utility
/^[a-z0-9-][a-z0-9._-]+@[a-z0-9.-]{4,}\.[a-z0-9]{2,}$/i

Step by step:

/ The slash denotes the start of a regular expression.  Don't confuse this with the backslash (forward slash:/ backslash: \).  The backslash is used to escape characters.

^ This is an anchor.  It is saying start at the beginning of the string, and only at the beginning.
       Omitting this allows the regular expression to match against only part of the string.

[a-z0-9-]  This is a "character class", denoted by the square brackets.  Characters inside of these are treated as a set, and the class as a whole matches only one of the characters in the set.  This class has a-z, 0-9, and dash.

[a-z0-9._-]  Character class.  This time we have a-z, 0-9, period, underscore, and dash.  Remember that a character class only matches one character.  In order to match multiple characters in the set, you need a repetition operator.

+ Repetition operator.  This means to take the previous character, or character class, and look for it at least once, or more times.

@ The at symbol.  This matches against an '@' character.  Any character that doesn't have a special meaning matches against one of itself.

[a-z0-9.-] Character class.

{4,} Repetition operator. Usually given in the form {x,y} where the previous character or class needs to be repeated at least x times, but no more than y.  By leaving one of the operators out, either x or y, that boundary becomes infinite.  Eg. {4,} indicates that we need to match the previous character or class at least four times.  Conversely, the {,4} operator would indicate that we need to match no more than four of the previous character, including matching it zero times.

\  Escape character.  Used in front of a character, it either applies or removes a special meaning.  In this case we are removing the special meaning from the

. Period character.  Normally this is a wild (ie. it matches anything).  When escaped as it is here, it means to match a literal period character.

[a-z0-9] Character class.  Matches only one of the characters in the set.

{2,} Repetition operator.  Matches at least two of the previous character.

$  End anchor.  Similar to the ^ at the beginning, but the opposite.  Forces the processor to seek to the end of the string.  Without this, our regex would validate on only the stuff in the middle and not care about the end.

/  The end of the regular expression.  The regex is started by a / and ends with a /.

i  Regex modifier.  Specifically the i at the end means that this regex is case-insensitive.  If you add this to the end, you are telling the regex processor that, as far as you are concerned, a is the same as A.

>But what is stopping us from putting in two periods right next to each other after the @ symbol, a string of 4 periods for example?
Nothing.  

/^[a-z0-9-][a-z0-9._-]+@[a-z0-9]{1,}([a-z0-9_-]|\.(?!\.)){1,}[a-z0-9]+\.[a-z0-9]{2,}$/i

Would though.  Here, the parenthesis is grouping two character classes in order, to which the repetition operator is applied.  The (?!\.) is what tells it to match only one period.  Its a long explanation and an advanced topic of regexes: http://www.regular-expressions.info/lookaround.html -- I'll not attempt to explain it here.

>Also, re.exec wouldn't know to check what we pass in as email with emailReg so shouldnt it  be  (emailReg.exec(email).index<0) rather than re?

Yep. Good catch...you can tell I didn't test that one before I posted it. ;-)  Running it as is throws an error about re not being undefined.  Swap that for what you wrote there.

>lastly, if the exec returns an index property of <0, you said the pattern didn't match, so that means it didn't meet the format given our stipulations and we kick it out right.

Yes.

It is worth noting that the regex that validates against the ISO standard for an email address is something like 900 characters long...waaay overkill.  But it supports other languages besides english, etc. If you are attempting to guard against typos, the best option is to just have them enter their email address twice.  The problem with form data validation is that you can easily take it too far.  

Download one of those regex testers and play around with putting different email addresses into that regex and see what it does.
0
 

Author Closing Comment

by:Bishork
Comment Utility
wow thanks so much for breaking that down for me, it's a lot easier to follow now.  you really went above and beyond.  i appreciate it!!!
0
 

Author Comment

by:Bishork
Comment Utility
PS -

why do we need both

[a-z0-9-][a-z0-9._-]

Why not just have the one [a-z0-9._-] before the @ sign?
0
 

Author Comment

by:Bishork
Comment Utility
ok i think i knwo the answer to that - just so we dont let people begin with a . or a _

this is what im testing with

/^[a-z0-9]{1,}([a-z0-9_-]|\.(?!\.))+@[a-z0-9]{1,}([a-z0-9_-]|\.(?!\.)){1,}[a-z0-9]+\.[a-z0-9]{2,6}$/i;

i dont want to let them begin with a _ - or a period.  

i keep getting

Error: 'exec(...).index' is null or not an object

as soon as i type in a malformed email address.
my function is below


function checkForValidEmailAddress(emailAddressField)

{

	var emailAddress = emailAddressField.value.toString();

	var emailReg = /^[a-z0-9]{1,}([a-z0-9_-]|\.(?!\.))+@[a-z0-9]{1,}([a-z0-9_-]|\.(?!\.)){1,}[a-z0-9]+\.[a-z0-9]{2,6}$/i;

	if (emailReg.exec(emailAddress).index<0)

	{

		emailAddressField.select();

		emailAddressField.focus();

		return false;

	}

	return true;

}

Open in new window

0
 

Author Comment

by:Bishork
Comment Utility
got it working with -
function checkForValidEmailAddress(emailAddressField)

{

	var emailAddress = emailAddressField.value;

	

	var emailReg = /^[a-z0-9]{1,}([a-z0-9_-]|\.(?!\.))+@[a-z0-9]{1,}([a-z0-9_-]|\.(?!\.)){1,}[a-z0-9]+\.[a-z0-9]{2,6}$/i;

	if (emailReg.exec(emailAddress) == null)

	{

		emailAddressField.select();

		emailAddressField.focus();

		return false;

	}

	return true;

}

Open in new window

0
 
LVL 3

Expert Comment

by:robacarp
Comment Utility
looks good .... keep up the good work
0
 

Author Comment

by:Bishork
Comment Utility
thanks

i put a new question up if you want to answer it:)

i have

/^[a-z0-9]{1,}([a-z0-9_-]|\.(?!\.))+@[a-z0-9]+([a-z0-9]|\.(?!\.)|\-(?!\-)){1,}[a-z0-9]+\.[a-z0-9]{2,6}$/i;

im trying to prevent -. and .- from being allowed next to eachother in the domain
i found this online -
^[A-Za-z0-9](([_\.\-]?[a-zA-Z0-9]+)*)@([A-Za-z0-9]+)(([\.\-]?[a-zA-Z0-9]+)*)\.([A-Za-z]{2,})$

it seems to disallow that and now im trying to figure out how to integrate it with the one im using.  
0

Featured Post

What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
Where to begin studying? 5 63
es6 typescript how to filter an array 10 37
Problem to page 4 16
jqplot Pie Chart - javascript 2 7
This article discusses the difference between strict equality operator and equality operator in JavaScript. The Need: Because JavaScript performs an implicit type conversion when performing comparisons, we have to take this into account when wri…
JavaScript can be used in a browser to change parts of a webpage dynamically. It begins with the following pattern: If condition W is true, do thing X to target Y after event Z. Below are some tips and tricks to help you get started with JavaScript …
The viewer will learn how to dynamically set the form action using jQuery.
The viewer will learn how to look for a specific file type in a local or remote server directory using PHP.

771 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

9 Experts available now in Live!

Get 1:1 Help Now