perl bug with pos() and placing matches in an array?

T

t13_e

For this code:

$x1 = "abcdefgh";

if(@vars = ($x1 =~ m/(b)/g))
{
$p = pos $x1;
print "pos is $p\n";
}

$x2 = "abcdefgh";

if($x2 =~ m/(b)/g)
{
$p = pos $x2;
print "pos is $p\n";
}

The following is displayed using perl v5.8.4:

pos is
pos is 2


Does someone know why pos is returning '' for the first regexp, and the
correct value, 2, for the second?

Thanks,

Tim
 
A

A. Sinan Unur

(e-mail address removed) wrote in @f14g2000cwb.googlegroups.com:

Subject: perl bug with pos() and placing matches in an array?

As I have pointed out many times before, it never fails to astonish me
when people automatically assume there is a "bug" as opposed to
realizing that they may be missing something.
For this code:

$x1 = "abcdefgh";

if(@vars = ($x1 =~ m/(b)/g))
{
$p = pos $x1;
print "pos is $p\n";
}

See perldoc perlop:

m/PATTERN/cgimosx
/PATTERN/cgimosx
....
Options are:
c Do not reset search position on a failed match when /g is
in effect.

....

The "/g" modifier specifies global pattern matching--that is,
matching as many times as possible within the string.

Hence, by the time of the call to pos above, the match will have failed,
and therefore the search position will have been reset (because you did
not use the c option.

D:\Home\asu1> cat v.pl

use strict;
use warnings;

my $x1 = "abcdefgh";

if(my @vars = ($x1 =~ m/(b)/cg)) {
my $p = pos $x1;
print "pos is $p\n";
}

my $x2 = "abcdefgh";

if($x2 =~ m/(b)/g) {
my $p = pos $x2;
print "pos is $p\n";
}
__END__

D:\Home\asu1> v
pos is 2
pos is 2

You will become much better at programming if you first assume that you
might, just might, be making a mistake instead of being convinced that
there is a bug in something someone else did every time things don't
work in line with your expectations.

Sinan

Sinan
 
T

t13_e

I see... sorry, I was assuming that "@vars = $x =~ m/(a)/" worked the
same as "@vars = $x =~ m/(a)/g", except that the /g would enable me to
get the position of the match.

I'm trying to do a single match, place the submatches in an array, and
at the same time finding the position of the match. I don't want to
use $1,$2,$3, etc... since the regexp is dynamic and created at
runtime. Do you have any idea of how to accomplish this without using
"length &`"?

Thanks,

Tim
 
A

A. Sinan Unur

(e-mail address removed) wrote in @g14g2000cwa.googlegroups.com:

What do you see? Please quote an appropriate amount of context when
replying.
... sorry, I was assuming that "@vars = $x =~ m/(a)/" worked the
same as "@vars = $x =~ m/(a)/g", except that the /g would enable me to
get the position of the match.

I'm trying to do a single match, place the submatches in an array, and
at the same time finding the position of the match.

The position of which match? You can only hope to get the position of
the *last* match using the c option.
I don't want to use $1,$2,$3, etc...

Who said you needed to?

If you want to get the position of all the matches in a string, then
you'll need to loop trough the matches, saving the position of the match
in each case.
Do you have any idea of how to accomplish this without using
"length &`"?

What is &` ?

I think, at this point, you need to take deep breath, read the posting
guidelines to get some pointers on how to compose a meaningful post that
helps others help you, and follow up with an accurate description of
what you are trying to achieve.

Sinan.
 
T

t13_e

A. Sinan Unur said:
(e-mail address removed) wrote in @g14g2000cwa.googlegroups.com:


What do you see? Please quote an appropriate amount of context when
replying.

This is just an expression. I'll refrain from using these from now on.
The position of which match? You can only hope to get the position of
the *last* match using the c option.

I would like to find the position of the first match.

I'll try to describe this more plainly. I have a string, $x, that may
match one or more times to a regexp, $re. $re is defined at runtime,
and contains one or more groupings using '(' and ')'.

I want to find the first match in the string, place all the submatches
of the first match into an array, @vars. I also would like to find the
position in $x of the first match.

It seems like the answer is to attempt the match twice, as follows:

$x = "abcdefg";

$re = qr/([bd])(.)/;

if(@vars = $x =~ /$re/) #get the submatches of the first match
{
$x =~ /$re/g; #find the position of the first match
$p = pos($x) - length $&;
print "pos is $p\n";
print "vars = ".join(' ',@vars)."\n";
}

If know of a nicer, more efficient way of doing this, then great.
Otherwise, thanks for your time.
Who said you needed to?

If you want to get the position of all the matches in a string, then
you'll need to loop trough the matches, saving the position of the match
in each case.


What is &` ?

Sorry, I meant "$`"...
 
T

Tad McClellan

For this code:

$x1 = "abcdefgh";

if(@vars = ($x1 =~ m/(b)/g))


A pattern match in list context.

It matches as many times as it can right here, then it is done matching.
{
$p = pos $x1;
print "pos is $p\n";
}

$x2 = "abcdefgh";

if($x2 =~ m/(b)/g)


A pattern match in scalar context.

Must remember pos() in case we resume matching against $x2.

{
$p = pos $x2;
print "pos is $p\n";
}

The following is displayed using perl v5.8.4:

pos is
pos is 2


Does someone know why pos is returning '' for the first regexp,


Because it is all done matching before you get to calling pos().

and the
correct value, 2, for the second?


Because it is still matching, so it is still maintaining position info.
 
F

Fabian Pilkowski

I want to find the first match in the string, place all the submatches
of the first match into an array, @vars. I also would like to find the
position in $x of the first match.

It seems like the answer is to attempt the match twice, as follows:

$x = "abcdefg";
$re = qr/([bd])(.)/;

if(@vars = $x =~ /$re/) #get the submatches of the first match
{
$x =~ /$re/g; #find the position of the first match
$p = pos($x) - length $&;
print "pos is $p\n";
print "vars = ".join(' ',@vars)."\n";
}

Have a look at `perldoc perlvar` where you can learn more about Perl's
predefined variables. The array @+ should contain the same value as what
the pos function returns.

if ( @vars = $x =~ /$re/ ) {
$p = $+[0] - length $&;
print "pos is $p\n";
print "vars = @vars\n"; # special var $" is a blank per default
}

Since you want to know the offset of the start of your match, you could
use the array @- instead of @+.

if ( @vars = $x =~ /$re/ ) {
print "pos is $-[0]\n";
print "vars = @vars\n";
}

regards,
fabian
 

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,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top