Why this RegExp doesn't work

R

runsun pan

Hi

I am wondering why I couldn't get what I want in the following 3 cases
of re:

(A)

var p=/([a-zA-Z]+-?[a-zA-Z]+):([a-zA-Z0-9]+)/g
p.exec("style='font-size:12'")
--> [font-size:12,font-size,12] // expected

(B)

p.exec("style='font-size:12;border-color:red'")
--> [border-color:red,border-color,red]
// expected: [font-size:12,font-size,12,
border-color:red,border-color,red]

(C) Note the pattern below is the same as that above:

/([a-zA-Z]+-?[a-zA-Z]+):([a-zA-Z0-9]+)/g.exec("style='font-size:12;border-color:red'")
--> [font-size:12,font-size,12]

I expected to get both font-size and border-color reported. However, in
case (B) only border-color is reported, and in case (C) only font-size
reported. The weirdest thing is that (B) and (C) are only different in
how it is used -- in (B) the pattern is assigned to a variable before
use, in (C) the pattern is used directly.
 
E

Evertjan.

runsun pan wrote on 03 nov 2006 in comp.lang.javascript:
var p=/([a-zA-Z]+-?[a-zA-Z]+):([a-zA-Z0-9]+)/g

p.exec("style='font-size:12;border-color:red'")
--> [border-color:red,border-color,red]
// expected: [font-size:12,font-size,12,
border-color:red,border-color,red]

try this:

<script type='text/javascript'>

var p=/[a-z]+-[a-z]+:[a-z0-9]+/gi
alert( p.exec("style='font-size:12; border-color:red'") )
alert( p.exec("style='font-size:12; border-color:red'") )

</script>
 
R

runsun pan

Evertjan. said:
try this:

<script type='text/javascript'>

var p=/[a-z]+-[a-z]+:[a-z0-9]+/gi
alert( p.exec("style='font-size:12; border-color:red'") )
alert( p.exec("style='font-size:12; border-color:red'") )

</script>

They give:
--> [font-size:12] // first alert
--> [border-color:red] // 2nd alert

This doesn't solve my questions. What I want is to solve it in one try.
I thought that's what the /g is for. If you have to run once more for
each match inside of the string, then, doesn't that mean that the /g
(global flag) is useless here ?
 
M

marss

runsun pan напиÑав:
This doesn't solve my questions. What I want is to solve it in one try.
I thought that's what the /g is for. If you have to run once more for
each match inside of the string, then, doesn't that mean that the /g
(global flag) is useless here ?

One more version:

var p=/[a-zA-Z]+-?[a-zA-Z]+:[a-zA-Z0-9]+/g
var res = "style='font-size:12;border-color:red'".match(p);
for(var i=0; i<res.length; i++)
{
alert(res+","+res.split(":"));
}
 
D

daveyand

This doesn't solve my questions. What I want is to solve it in one try.
I thought that's what the /g is for. If you have to run once more for
each match inside of the string, then, doesn't that mean that the /g
(global flag) is useless here ?

It seems you might need to read up on perl regex.

Basically the /g means that it works on the whole string. So for
example if you were looking for this
/hello/g
and you have the string:
hello there this is a hello statement

then the /g would match both the first and second hellos. Normally the
regex will stop after it matches the condition.

Likewise to get the value in the array you want add () arround the
sections that you wish to seperate out.

For example you have:

font-size: 12px;
/([a-z]*?-[a-z]*?):.([0-9]*)px/
That will return on blah.match(regex).toSource();
[font-size: 12px, font-size, 12]

Or there abouts, havent tested it. The () adds that section of the
regex element in the string to matches[1 .. N]

Make sense?
 
S

scriptguru

runsun said:
Evertjan. said:
try this:

<script type='text/javascript'>

var p=/[a-z]+-[a-z]+:[a-z0-9]+/gi
alert( p.exec("style='font-size:12; border-color:red'") )
alert( p.exec("style='font-size:12; border-color:red'") )

</script>

They give:
--> [font-size:12] // first alert
--> [border-color:red] // 2nd alert

This doesn't solve my questions. What I want is to solve it in one try.
I thought that's what the /g is for. If you have to run once more for
each match inside of the string, then, doesn't that mean that the /g
(global flag) is useless here ?

Wanna do everything with one command and without cycles? ;)

var found=[]
"style='font-size:12;border-color:red'".replace(/([a-z]+-?[a-z]+):([a-z0-9]+)/gi,function(s){found.push(s.split(":"))})
alert(found)

The problem in exec method, not in regexp.
Note: I use .replace() method but there is no replacement in code
above, only matching
 
M

Michael Winter

runsun said:
I am wondering why I couldn't get what I want in the following 3
cases of re:

You're expecting things to work in ways that shouldn't happen.
var p=/([a-zA-Z]+-?[a-zA-Z]+):([a-zA-Z0-9]+)/g
p.exec("style='font-size:12'")
--> [font-size:12,font-size,12] // expected

The RegExp.prototype.exec method attempts to find the first pattern
match in its argument. Here, it discovers "font-size:12", so the method
stops and returns an array containing details of the match. As the
global flag is set for the regular expression object, the lastIndex
property of the regular expression is modified to point just beyond the
end of the match: to the last apostrophe, in this case.
(B)

p.exec("style='font-size:12;border-color:red'")
--> [border-color:red,border-color,red]

That isn't actually what you receive. You've executed this straight
after the previous test, therefore the change in the lastIndex property
described above is significant. If this call was made separately, the
same result as above would be returned. That is, information about the
font-size declaration.
// expected: [font-size:12,font-size,12,
border-color:red,border-color,red]

That will never happen. The exec method only cares about the first (or
more generally, the next) match. Once it finds it (or the string has
been exhaustively searched with no match) the method will return.

As in a recent thread, "regexp test function behavior"[1], you too have
misunderstood how both the global flag and the exec method works. The
point of the former is, as I wrote in that thread, to allow repeated
processing by tracking where the last match ended. A follow-up call can
then resume from that point.

Some regular expression-related methods, most notably the
String.prototype.match and replace methods use the global flag to infer
that this repetitive process should be performed by the method itself,
using the behaviour of the RegExp.prototype.exec method to accomplish
that goal. If you want that same behaviour, you have to implement it
yourself:

String.prototype.detailedMatch = function(regExp) {
var lastMatch = regExp.lastIndex = 0,
result = [],
match;

while ((match = regExp.exec(this))) {
result[result.length] = match;
if (regExp.lastIndex == lastMatch) ++regExp.lastIndex;
lastMatch = regExp.lastIndex;
}
return result;
};

Calling that:

'style="font-size:12;border-color:red"'.detailedMatch(
/([a-zA-Z]+-?[a-zA-Z]+):([a-zA-Z0-9]+)/g);

would result in:

[[font-size:12,font-size,12],
[border-color:red,border-color,red]]

which is easy to observe with:

Array.prototype.toString = function() {
return '[' + this.join() + ']';
};

Compare that result with just the String.prototype.match method:

[font-size:12,border-color:red]

Mike


[1] regexp test function behavior
"HopfZ" <[email protected]>
Sun, 29 Oct 2006 12:02:42 (UTC)
<[email protected]>

<http://groups.google.co.uk/group/comp.lang.javascript/msg/87d9d504bf05393d>
 

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

Forum statistics

Threads
473,968
Messages
2,570,153
Members
46,701
Latest member
XavierQ83

Latest Threads

Top