Javascript Regex .test(): Returning true for a double space (or more) in the string?
My goal is to return 'true' for a valid string, which in this case is a string that starts with a letter, then has any combination of letters and numbers and spaces, but no consecutive spaces.
I've tried several combinations, with the following 'prefix':
^[a-zA-Z][a-zA-Z0-9]*$
This works just fine for the 'start with a letter' and 'combinations of letters and numbers', but I am having trouble adding the regex to match a space, and only a single space.
For example:
^[a-zA-Z][a-zA-Z0-9]*$|[\s{0,1}]
doesn't work. It will return true for "asdasdasd 3333$", among other things.
It is if I am trying to force the logic:
if (firstLetter != letter){
return false;
}
else{
var spaceFound = false;
for ( var int = 0; int < individualLetters.length; int++) {
if (individualLetters[int] == space){
if (spaceFound == true){
return false;
}
else {
spaceFound = true;
}
}
if(individua开发者_Go百科lLetters[int] != letterOrNumber){
return false;
}
else{
spaceFound = false;
continue;
}
}
}
However I think I am missing a fundamental understanding on regex. Any way, any help would be appreciated.
Here are two different flavors is one flavor:
function test(s) {
return /^[A-Z]([A-Z]|\d| (?! ))*$/i.test(s);
}
http://jsfiddle.net/HCNDD/2
You can't negate groups, so you can't forbid 2 spaces with just one regexp.
I didn't get the motivation for your second regexp, but the reason it doesn't work is that you're allowing a string with a single space no matter where it occurs; ^ matches the start of the string and $ matches the end, so you're not actually writing a prefix, but a whole string; I.e. If
^[a-zA-Z][a-zA-Z0-9]*$|[\s{0,1}]
means anything, it means
- the whole string is a letter followed by any number of letters or digits
OR
- the string has a space somewhere in it
Possibly what you want is
/^[a-zA-Z][a-zA-Z0-9 ]*$/.test(s) && !/ /.test(s)
how about:
/^[a-z]( ?[a-z0-9])*$/i
It matches your [a-z]
then [a-z0-9]
again and again...
I would advise from trying to do everything in a regular expression; they are, after all, not as powerful as the language you are coding in. The following one-liner is not verbose at all, and makes your intent clear:
query.match(/^[A-Za-z][A-Za-z0-9 ]*$/) && !query.match(/ /)
You may need to cast to a Boolean(...). See note at end of answer for a single elegant boolean expression.
A test suite is probably what you want:
function test(query) {
/*
* "My goal is to return 'true' for a valid string, which in this
* case is a string that starts with a letter, then has any combination
* of letters and numbers and spaces, but no consecutive spaces."
*/
return (query.match(/^[A-Za-z][A-Za-z0-9 ]*$/) && !query.match(/ /)) == true;
}
[
['Z', true],
[' ', false],
['_', false],
['9', false],
['A ', true],
['A ', false],
['a\t', false],
['a*', false],
['a b C02 4', true],
['a b C02 4 ', true],
['a b C02 4 ', false],
['a b C02 4 ', false],
['a b C02 4 ', false],
['a _', false],
['a ', false]
].map(function(pair){
if ( test(pair[0]) != pair[1] )
console.log('FAILED TEST:', pair);
});
Of course, the definition of what is a 'letter' can change if you're not working with ascii, but for example, unicode with international characters. If you desire unicode support, see Javascript + Unicode regexes
Edit!
If you really want to use a regular expression, it turns out if your regex engine supports negative lookaheads (?!BADPATTERN)
, then you can translate PATTERN without SUBPATTERN within
to (?!.*SUBPATTERN)PATTERN
. This information thanks to a comment by Tim Pietzcker.
Thus if you really wanted a single regular expression, you could do:
function test(query) {
/*
* "My goal is to return 'true' for a valid string, which in this
* case is a string that starts with a letter, then has any combination
* of letters and numbers and spaces, but no consecutive spaces."
*/
return Boolean( query.match(/^[A-Za-z](?!.* )[A-Za-z0-9 ]*$/) );
// START|[alpha [alnums/spcs without |END
// | ] any ^^double spcs ]|
}
And since we wrote our test battery above, we can easily check to see that it passes with flying colors. I think there's another answer (only one) which manages to correctly do this by putting the negative lookahead attached to every character (which only works because the regex is of the form [charset]*
, but is still valid). Anyway this is the general way to do it.
Everybody's making this a lot more difficult than it needs to be. Try to think in terms of what you want to happen, and let the negatives take care of themselves. Check it out:
^[a-zA-Z][a-zA-Z0-9]*(?: [a-zA-Z0-9]+)*$
Each time the regex runs out of alphanumeric characters, it tries to match a space followed immediately by another block of alphanumerics. I don't have to tell it not to match any more spaces because I've already told it what I do want to match next. And when it reaches a point where it can't match an alphanumeric or a space, and it's not at the end of the string, it fails.
精彩评论