Strange RegExp problem

R

r@ph

Hello,

It seems delimiters can cause trouble sometimes.

Look at this :

<script type="text/javascript">
function isDigit(s) {
var DECIMAL = '\\.';
var exp = '/(^[+]?0(' + DECIMAL
+'0+)?$)|(^([-+]?[1-9][0-9]*)$)|(^([-+]?((0?|[1-9][0-9]*)' + DECIMAL
+'(0*[1-9][0-9]*)))$)|(^[-+]?[1-9]+[0-9]*' + DECIMAL +'0+$)/';
return RegExp(exp).test(s);
};
document.write(isDigit('123.45') ? '1' : '0');
document.write(isDigit('123') ? '1' : '0');
document.write(isDigit('123.00') ? '1' : '0');
</script>

With / delimiters, third test fails.
With | delimiters, it's ok.

Same behavior with firefox,ie7,safari.

Can someone explain this ?

Thanks.
 
M

Martin Honnen

r@ph said:
var exp = '/(^[+]?0(' + DECIMAL
+'0+)?$)|(^([-+]?[1-9][0-9]*)$)|(^([-+]?((0?|[1-9][0-9]*)' + DECIMAL
+'(0*[1-9][0-9]*)))$)|(^[-+]?[1-9]+[0-9]*' + DECIMAL +'0+$)/';
return RegExp(exp).test(s);

// serve as delimiters for regular expression literals. You don't use
them in strings passed to the RegExp constructor, unless you really want
to match a slash.
 
R

r@ph

var exp = '/(^[+]?0(' + DECIMAL
+'0+)?$)|(^([-+]?[1-9][0-9]*)$)|(^([-+]?((0?|[1-9][0-9]*)' + DECIMAL
+'(0*[1-9][0-9]*)))$)|(^[-+]?[1-9]+[0-9]*' + DECIMAL +'0+$)/';
return RegExp(exp).test(s);
// serve as delimiters for regular expression literals. You don't use them
in strings passed to the RegExp constructor, unless you really want to
match a slash.


Hi Martin,
Can you explain this a little more please ?
In my sample, why only the 3rd case fails ?
Thanks a lot.
 
L

Lasse Reichstein Nielsen

r@ph said:
It seems delimiters can cause trouble sometimes.

No doubt. Most things can :)
Look at this :

<script type="text/javascript">
function isDigit(s) {
var DECIMAL = '\\.';
var exp = '/(^[+]?0(' + DECIMAL
+'0+)?$)|(^([-+]?[1-9][0-9]*)$)|(^([-+]?((0?|[1-9][0-9]*)' + DECIMAL
+'(0*[1-9][0-9]*)))$)|(^[-+]?[1-9]+[0-9]*' + DECIMAL +'0+$)/';

ICK. Now I have looked. I need to go wash my eyes. With soap.

Ahem, anyway ...
The "/" at the start and end of "exp" is pretty certainly wrong.

A javascript regexp *literal* is delimited by slashes, e.g.,
/foo|bar/. The corresponding constructor call would be RegExp("foo|bar"),
where the regexp is in a string literal, delimited by the string quotes,
and therefore doesn't need any other delimination ... deliminion ...
something.

The "/"'s above merely cause the first and last alternative of the
regexp to fail because they expect a slash before the start of the
string, or after the end.
return RegExp(exp).test(s);
};
document.write(isDigit('123.45') ? '1' : '0');
document.write(isDigit('123') ? '1' : '0');
document.write(isDigit('123.00') ? '1' : '0');
</script>

With / delimiters, third test fails.
With | delimiters, it's ok.

Where did you put the '|' "delimiters"? In the same palce as the '/'?
Then the first and last alternative would start to work, and you would
also have added two ways of matching the empty substring, meaning that
*all* strings would match. Try isDigit("Arglebargle").
Same behavior with firefox,ie7,safari.

Then it's probably intended behavior.
Can someone explain this ?

Yep, it's what you asked for :)

Stick to regexp literals if possible, they are easier to read,, and
you don't have to escape your backslashes.
var exp = '/(^[+]?0(' + DECIMAL
+'0+)?$)|(^([-+]?[1-9][0-9]*)$)|(^([-+]?((0?|[1-9][0-9]*)' + DECIMAL
+'(0*[1-9][0-9]*)))$)|(^[-+]?[1-9]+[0-9]*' + DECIMAL +'0+$)/';

If I read the regexp correctly, it should match any of:
- An optional plus and a single zero, optionally followed by a decimal
point and one or more zeros.
- An optional sign and a non-zero digit followed by any number of digits.
- An optional sign and either zero or (a non-zero digit followed by any
number of digits), followed by a decimal point and a sequence of digits
containing at least one non-zero digit.
- An optional sign and a non-zero digit followed by any number of digits,
followed by a decimal point and a nonzero number of zeros.

I.e., an optional sign, either a single zero multiple digits not startine
with a zero, and optionally a decimal point and more than one digit -
except you don't allow minus zero.

It might be easier to use two checks:

/^[-+]?(?:0|[1-9]\d+)(?:\.\d+)?$/
AND NOT
/^-0(?:\.0+)$/

If that's not possible, I think the above can also be made a little
shorter (and avoid the DECIMAL constant, unless you do it for
readablilty):
/^(?:\+?0(?:\.0+)?|[-+]?(?:0\.0*[1-9]\d*|[1-9]\d*(?:\.\d+)?))$/

Best of luck.
/L 'likes regexps'
 
R

r@ph

Hello,

Thanks for this complete answer.
A javascript regexp *literal* is delimited by slashes, e.g.,
/foo|bar/. The corresponding constructor call would be RegExp("foo|bar"),
where the regexp is in a string literal, delimited by the string quotes,
and therefore doesn't need any other delimination ... deliminion ...
something.
Understood.

Where did you put the '|' "delimiters"? In the same palce as the '/'?
Then the first and last alternative would start to work, and you would
also have added two ways of matching the empty substring, meaning that
*all* strings would match. Try isDigit("Arglebargle").

Exact. I'm confused :S


This code and my problem come from the tablesorter jquery plugin. I warn the
author now.

Thanks again.
Raph
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,534
Members
45,007
Latest member
OrderFitnessKetoCapsules

Latest Threads

Top