String array part match problem?

Hey guys,
Name input value should be entered as shown on credit card eg. ‘John P Smith’. I’m trying to prevent ‘Aaaaa B Ccccccc’ being sent to the sever. Any suggestions appreciated. I’m pritty sure the var rep=regex is causing the script to hang on the first if it acctualy finds the lowercase repeated more than 2times and I realy need to check that lowercase isn’t repeated sequentialy more than 2 times?

THE HTML


<p id="reply">Please enter your name as shown on credit card.</p>
<input type="text" id="name" name="name" class="required" value=" " \\>

THE SCRIPT


//namechange function

function namechange()
{
var n=name.value;
n.split(' ').join(''); //get rid of extra white space;
var names=new Array();
names=n.split(' '); //set array delimeter ' ' to space
var first=names[0]; //also tried var first=names.slice(0,1);
var middle=names[1]; //also tried var middle=names.slice(1,2);
var last=names[2]; //also tried var last=names.slice(2,3);
var rep=/^[a-z].{3}$/; //if lowercase alpha repeated 3 times word isn't name need sequential regex!
if(names.length<3) //check that input isn't less than 3 words long ie. 'John P Smith'='John Smith'
{
reply.innerHTML='Your name must be 3 words long eg. John P Smith.';
name.value='Error!'; //lower case 'r' repeated 3 times?
name.style.color='red';
return:false;
}
if(names.length>3) //make sure input value not 'John P Smith Jr'
{
reply.innerHTML='Your name must be 3 words long eg. John P Smith.';
name.value='Error!'; //lower case 'r' repeated 3 times?
name.style.color='red';
return:false;
}
if(first.match(rep)) //check that lowercase not repeated 3 times should be sequential?
//once this gets picked up the reply remains the same onchange even if 'John P Smith' is entered?!!
reply.innerHTML='This is not a real name: '+first+'.';//ie. not 'Joooohn'
name.value='Error!'; //lower case 'r' repeated 3 times?
name.style.color='red';
return:false;
}
if(middle.length>=1) // Make sure middle is initialized ie. not 'John Paul Smith' works on it's own
{
reply.innerHTML='Please initialize your middle name '+middle+' eg. John P Smith.';
name.value='Error!'; //lower case 'r' repeated 3 times?
name.style.color='red';
return:false;
}
if(last.match(rep)) //check last for repetive lowercase should be sequential?
//if caught 'John P Smmmmith' reply returns 'This is not a real firstname: '+first+'.'??
{
reply.innerHTML='This is not a real last name: '+last+'. '; //ie. not 'Smmmmith'
name.value='Error!'; //lower case 'r' repeated 3 times?
name.style.color='red';
return:false;
}
else
{
reply.innerHTML='Thank you '+name.value+', card verification pending.';
name.style.color='blue';
return:true;
}
}

Yeah my javascript is getting better but my regex applied script sucks.:nono::x
Sorry: I Will post to WebDeveloper.Com, DaniWeb.Com. I need a responce soon.

There are a few problems with your code, which I’ll go through one at a time.

1. Poor formatting.

Dude.

2. Getting the value of the “name” <input>

You currently get the value like this:


var n = name.value;

Your input has an id of “name,” so it looks like you’re relying on the fact that (in most browsers) JavaScript variables are automatically created from HTML nodes that have an id. Firefox doesn’t, however. So to support that browser, you’ll need to explicitly get the element:


var name = document.getElementById('name');
var n = name.value;

Off Topic:

Maybe there’s more JS that you didn’t share, where you do exactly what I’m suggesting. In which case, good job!

3. “Getting Rid of Extra White Space”

This comes next in your script:


n.split(' ').join(''); //get rid of extra white space;

This line does nothing. The split and join methods do not change the original variable, they only return the new value. So if you really did want to do this, you’d have to do the following:


n = n.split(' ').join('');

But even then, I don’t think you want to do this. It won’t get rid of extra white space; it gets rid of all the white space (well, only spaces, but even so). So if the user enters “John P Smith”, then this will turn it into “JohnPSmith”, which breaks your next few lines.

So let’s just take this part out completely.

Off Topic:

If you were really worried about getting rid of multiple spaces, you could do something like this:


n = n.replace(/\\s+/g, ' ');

That would replace any instance of one or more white space character with a single space. (Keep in mind, however, that it won’t trim the string; white space at the beginning and end will not go away completely…)

4. Your Regular Expression

Here’s the regular expression you’re trying to use to match 3 of the same character in a row:


var rep = /^[a-z].{3}$/;

But, as you were probably aware, this isn’t doing what you want it to. Regular expressions are really complicated in their own right, and matching three or more of any letter turns out to be particularly tricky, so I’ll just spit it out (here’s where I got this pattern, by the way):


var rep = /([a-z])\\1{2,}/;

The thing is, that new pattern does not try to match the entire string! It doesn’t check if there are numbers or weird characters (like $ or %) in the name, which would indicate that it’s a phony! All it does is search for lowercase letters that are repeated three or more times.

Off Topic:

If you really want to validate the names that other way as well, here’s a simple regex you could use:


var rep2 = /^[a-z]+$/;

But it doesn’t allow uppercase letters or apostrophes or dashes, all of which are totally legal characters in a name!

5. Returning true/false

You use the following throughout your code when returning a boolean:


return :false;

/* -- or -- */

return :true;

The colon isn’t necessary. Just do “return false;” or “return true;”, otherwise the browser doesn’t know what to do with it.

6. Missing Bracket


// you don't have the opening bracket after the "if"!

if(first.match(rep)) //check that lowercase not repeated 3 times should be sequential?
//once this gets picked up the reply remains the same onchange even if 'John P Smith' is entered?!!
reply.innerHTML='This is not a real name: '+first+'.';//ie. not 'Joooohn'
name.value='Error!'; //lower case 'r' repeated 3 times?
name.style.color='red';
return:false;
}

7. Testing for a Single Initial

Here’s how you throw an error when the middle initial is too long:


if (middle.length >= 1) {
    // error
}

You’re trying to make sure that it’s only one initial. However, >= means “greater than or equal to”. What you’re looking for is a simple greater-than:


if (middle.length > 1) {
    // aah, that's better
}

8. A Final Word re: Your Methodology

Maybe you’re doing all of this just to learn about JS. If so, awesome; in programming, as in all things, experimentation will make you better.

However, if this is actual production code that you’re trying to use on a site, there are a number of much deeper problems that go beyond the bugs.

  • Are you validating this data on the server as well, in case JS is disabled?
  • What if someone’s name actually does have three letters in a row?
  • What if someone has more than one middle name?
  • Clearing the data every time they make an error is frustrating; instead of making a single change, they have to enter everything all over again, and remember where their error was, so that they can fix it.

The Final Product

I made a few other changes to your code (mostly just stylistic) and created a jsFiddle. It looks like everything works the way you wanted it to…

Hope this massive pile of word vomit helps :smiley:

sdleihssirhc Great response, thanks very much. I’ll run an alert on the ‘name.value’ after what I assumed incorectly was //name.split(‘2 white spaces’).join(‘1 white space’); Also caught the missing brace and return:false true in subsiquent endeavours. Sorry, it does point out the state of my javascript in that I can’t write it off the head with out complete conscentration and using cut and paste doesn’t help either. Will post back latter with results.

sdleihssirhc Great fidel dude. Awesome instruction and demo process! I will have fun setting up the same validation in php! Is there a fidel type site for php testing or can it be built into a browser? I am using IE8 still but have Firefox loaded for testing and haven’t been able to use it much.

sdleihssirhc One draw back is that AAaab B CCCccd passes so the regex still falls short and should be first letter only one uppercase and followed by more than two lower case letters but I’m guessing that the first uppercase letter should be automated in the array
//var first=names[0].length[0].toUpper(); or regex to set the first carachter to uppercase and the rest to lower and then test the string for more than one Uppercase and more than two lowercase?

Be careful with such limitations, otherwise you won’t end up getting Bo Derek or Rob Roy MacGregor. All lower-case surname prefixes are also quite common, such as Maria von Trapp or Johannes Diderik van der Waals (surname being “van der Waals”)

As Google found out recently, some people have the strangest of legitamate names.

paul_wilkins Your right about that but the problem is that the input value is automaticaly string to lower case and the first letter charAt(0) of each part of the string seperated by ’ ’ or space is automatically set to upper case. John P Smith can easily be sent to the server as Jjohn P Smith. I’ve been trying to get a pattern that prevents J [A-Z] bing repeated ‘sequentialy’ by j [a-z] such as the forementioned J’j’ohn P Smith as it acctualy conflicts with the pattern that tests for more than two lower case [a-z] charachters. In fact ‘Jjjohn P Smith’ will acctualy go to the sever because the lower case [a-z] are allowed twice!

That might be next to impossible, because there are fully valid names where the first and second letter of their name repeat, such as Lloyd for example, or Aaron.

Having said that though, there can be ways to include only letters that we’re sure don’t have any double initial letters.
in what way specifically do your patterns conflict?

In the end I think you’re right. Eg. Lloyd and others would be excluded if what I was trying to do was accomplished. here are the two patterns I was trying to test with.


var AZ=/([A-Za-z])\\1{1,}/;//couldn't figure out the correct syntac for A-Z followed by a-z matching
var az=/([a-z])\\1{2,}/;

For the sake of completion, it seems that no regular expression can capture an uppercase followed by the same lowercase letter, unless you brute-force a solution with:
/^(Aa|Bb|Cc|…|Xx|Yy|Zz)/

A more elegant solution might be to do a case-insensitive check of the first two letters
/^([a-z])\1/i

Where ^ forces the regular expression to match at the first character, (…) captures a group or in this case, one character, \1 repeats what was found in the captured group, and the /…/i with the i flag makes it a case-insensitive search.

That won’t guarantee that they follow the letter casing that you need, but if there is other code that deals with the casing then this would do the job.

You could also allow multiple initial letters, but just display a warning about it to let the user know about the situation, in case they have to correct things there, but allow them to submit it anyway.
“Name starts with duplicate characters. Please check that it is spelled correctly” for example.

Hey paul Wow, smart indeed. I’ll have to check it out. Will post back latter.

paul_wilkins thanks sir, you where right on the money. I’m testing fine for A-Z followed by matching a-z with the i flag/case insensitive and checking for a-z sequential repeated more than twice. Now I will stop writting ‘Error!’ to the input value and suggest a spelling check on those if statements.
In the end Verisign or Payals etc. will validate the name on the card, however I was concerned that I don’t use a first and last name etc. on the house database. It cuts down on the html form inputs as well as database storage while maintaining direct functionality. Validating in php becomes the next chore. Thanks again for your input. Oh yeah, stultuske at daniweb.com suggested that some card names are only two words long ie. ‘John Smith’ as aposed to ‘John P Smith’ so I’ve changed if names length less than 3 to less than 2. I’m not sure that there are card names like that and could only guess that is the case?

How about where the name is empty, when people have only one word names for themself, such as Madonna or Cher.

Roger that paul_wilkins I guess Cher or Prince will be excluded from making a purchase unless I change the if to less than 1 which amounts to empty and may not exclude the testing of the first name caught in the names array. Well caught. Troy III at DaniWeb.com also caught some other points. This was my last reply at DaniWeb.com on the same subject.

Troy III Wow again! The single Quote " ’ " being permitted? Which of course is a legal card name character. I really have to add that one as no punctuation at all is presently permitted. Now I have to check and see if " ’ " works with


//except only alphabetical characters in name strings
var alpha=/^[a-zA-Z]+([\\s][a-zA-Z]+)*$/;
//except alphabetical characters and single quote like so?
var alpha=/^[a-zA-Z']+([\\s][a-zA-Z']+)*$/;

Prevent ‘Jjohn P Smith’ may not be possible as paul_wilkins suggested as it would prevent ‘Lloyd P Smith’. Unless I had a list of names that had two sequential letters to compare which two letters to allow!

Case insensitive search at beginning of name for one sequentially repeated alpha.


//will prevent 'Lloyd P Smith' with this
var AZ=/^([a-z])\\1/i;
//won't prevent 'Llloyd P Smith' with this
var AZ=/^([a-z])\\[B][COLOR="Red"]2[/COLOR][/B]/i;
//and I can write 'Error!' to the input value! Not "Please check spelling"

A list of names with double sequential letters would provide the letters that could be added or permitted with a not group in the regex?


//not 'l' for Lloyd or 'c' for McCain etc.
var AZ=/^([a-z][^l|c])\\1/i;

Actually “McCain” breaks the automated first Character to upper case after the string is set to lower case? For sure they are legal card names. Allowing charAt(2) to be capitalized would be a problem as it involves this function.

Caps function.


/*thanks to Airshow at dani.web and modifications by OMA*/

function Caps(str)
{	
var a=str.toLowerCase().split(' ');//OMA added toLowerCase()?	
for(var i=0; i<a.length; i++)
{		
ch=a[i].charAt(0);	
//add var ch2=a[i].charAt(2); would add the upper case	to all
a[i]=a[i].replace(ch, ch.toUpperCase());
}	
return a.join(' ');
}

function nCaps(name)
{	
var f=document.getElementById ('name');	
if(f)
{
f.value=Caps(f.value);
}
}

function namechange()
{
//name.value.toLowerCase(); avoided
nCaps();

So I guess that would have to be written in a regex or pattern to allow the third character of the last name to be upper case!
The Scots have money to.

Yeah I’d have to permit the third character of any of the names array strings to be upper case as in McCain which could be avoided by taking the toLowerCase out completely and make most of this post redundat unless I avoid the ‘elegant’ and force the sequentially repeated character class with regex/pattern.

Any suggestions appreciated:nono::x

Off Topic:

I’m sorry to be a jerk about this, but I can’t resist saying it again:

It sounds like you’re going about this all wrong.

Why put so much effort into validating the name? There are so many “valid” names that you have to take into account. And a lot of people take offense to being told that their names aren’t “real”. Go figure.

If it’s for payment purposes, aren’t there easier ways to do what you’d ultimately be interested in? (For example, if you collect credit card information as well, just run the card. If it doesn’t work, then you know something’s invalid. Or simply collect an e-mail address and/or a phone number; then if something goes wrong, you can fallback to actually talking to them.)

Why do you care if someone gives you invalid information? As long as they can’t use that information to exploit something, what’s the big deal? Isn’t this effort that could be better spent on other areas of the site?

Off Topic:

Unless, as I said before, this is a personal project you’re using to learn JS, or something.

sdleihssirhc Your right, we don’t intend to store card numbers in the house database that are not md5 encrypted, just the information necessary to give verisign etc. the information necessary to process the purchase without the client re-entering their card information every time they visit the site untill that card expires. Of course the name on the card may not be exactly the same if the card is validated but it certainly would be a priority as far as card validation goes? The answer to your question is, both, project and learning. I’m very close to the solution thanks to the script gurus, including yourself by no small means. I have two small problems that need fixing.

  1. ‘Lloyd P Smith’ Lloyd should allow for sequential ‘l’ and I can’t think of other names similar
  2. ‘McCdonalds’ produces ‘Mccdonald’ when string toLowerCase is Used.
  3. So a not L or second C regex or pattern might overcome both scenarios.

var alpha=/^[a-zA-Z']+([\\s][a-zA-Z']+)*$/;//allows alpha & " ' " for O'brien
var AZ=/^([a-z^l])\\1/i;
//doesn't stop L repeating in start more than once for 'Lloyd' don't know of other names
var az=/([a-z])\\1{2,}/;//questions string for repeated sequential characters but produces Mccdonal
//When the whole string is automated to lowercase and only first letters are uppercase.

I’m guessing I would have to use another regex to search for CC in name and change the second C to upper case before the name value is sent to the server which could be done server side but would be easier if done in front of the client as the client would be the first one to panick.

There’s also MacDonald and other Mac- prefixes, and where I am in New Zealand we have a lot of Dutch immigrants, with names such as Edwin van der Sar where the “van der” are the lowercase part of their surname, indicating a similar thing as the Mac- prefix.

Then there’s surnames with multiple apostrophies within them, which Samoans are famous for having.

Guess what, a few years ago I was performing a similar sanitisation of surnames from a database. I learned there that the range of legitimate exceptions is quite large.

paul_wilkens You’ve done it again. Just when I thought I could finish.

  1. The " ’ " is already allowed more than once as it is part of the alpha check
  2. ‘van der’ can be accomodated by increasing the if to names length greater than 4
  3. MacCdonalds throws of my working solution in function Caps() as it is charAt(0,1,2) based and should have a regex to check for cc in string

Will post the Caps function wrong solution in a minute:rofl:

paul_wilkins Just realized

Please enter your name as shown on credit or debit card.

Excludes all lower case alpha input of a-z! All are upper case on mine and probably all other cards. In any case the following didn’t work on the ‘cc’ in McCdonalds anyway.


function Caps(str)
{	
var a=str.split(' ');//removed toLowerCase
for(var i=0; i<a.length; i++)
{		
ch=a[i].charAt(0);//Probably needs a regex?
C1=a[i].charAt(1);
C2=a[i].charAt(2);		
a[i]=a[i].replace(ch, ch.toUpperCase());
if(C1=='c'&&C2=='c')
{
a[i]=a[i].replace(C1, C1.toLowerCase());//becomes lower case 'c'
a[i]=a[i].replace(C2, C2.toUpperCase());//remains lower case 'c'
return a.join(' ');
}
else
{	
return a.join(' ');
}
}
}
function nCaps(name)
{	
var f=document.getElementById ('name');	
if(f)
{
f.value=Caps(f.value);
}
}

function namec()
{
nCaps();

Question, if a persons name is ‘Edward van der Sar’, wouldn’t it show on the card as ‘EDWARD VAN DER SAR’ just like ‘JOHN P SMITH’?