(?{ ... }) puzzlement

J

J Krugman

In an attempt to find a single regexp that would succeed if three
different sub-regexps matched in any order (see why in the thread
called '"Commutative" regexps'), I started playing with (?{...})-type
regexps. As warm-up, I tried this:

1 use strict;
2 use re 'eval';
3
4 my @re0 = qw(abc pqr xyz);
5 my @seen = (undef) x @re0;
6 my @re = map sprintf('%s(?{ $seen[%d] ||= "@-" })',
7 $re0[$_], $_),
8 0..$#re0;
9 my $re = eval "qr/@{[join('|', @re)]}/";
10
11 #0 1 2
12 #01234567890123456789012345
13 '__pqr____xyz__pqr___abc___' =~ /(($re).*?)*/;
14
15 print "\$seen[$_] = $seen[$_]\n" for (0..$#seen);
16
17 __END__

$seen[0] =
$seen[1] =
$seen[2] =

If I change line 13 to

13 '__pqr____xyz__pqr___abc___' =~ /(($re).*?)*(?!)/;

The output I get changes to

$seen[0] = 2 14 14
$seen[1] = 2
$seen[2] = 2 2 2


I find both results completely puzzling. I realize that ?{ ... }
is a highly experimental feature, but if anyone can explain to me
what's going on I'd very much appreciate it.

TIA,

jill

P.S. Unrelated regexp question: if I have a string or regexp in
a variable $x, and I want to use this variable to write a regexp
corresponding to 5 repeats of the contents of $x, how do I write
it? If I wrote /$x{5}/, it would be interpreted by perl as attempting
to access the value corresponding to key '5' in the hash %x.
 
B

Ben Morrow

Quoth J Krugman said:
In an attempt to find a single regexp that would succeed if three
different sub-regexps matched in any order (see why in the thread
called '"Commutative" regexps'), I started playing with (?{...})-type
regexps. As warm-up, I tried this:

1 use strict;
2 use re 'eval';
3
4 my @re0 = qw(abc pqr xyz);
5 my @seen = (undef) x @re0;
6 my @re = map sprintf('%s(?{ $seen[%d] ||= "@-" })',
7 $re0[$_], $_),
8 0..$#re0;

@- only contains entries for () sub-expressions. You have none here
(that have matched yet), so it won't work. (My guess is that the first
entry isn't filled in until after the match has finished, but I don't
rightly know...)
9 my $re = eval "qr/@{[join('|', @re)]}/";
10
11 #0 1 2
12 #01234567890123456789012345
13 '__pqr____xyz__pqr___abc___' =~ /(($re).*?)*/;
14
15 print "\$seen[$_] = $seen[$_]\n" for (0..$#seen);
16
17 __END__

$seen[0] =
$seen[1] =
$seen[2] =

If I change line 13 to

13 '__pqr____xyz__pqr___abc___' =~ /(($re).*?)*(?!)/;

The output I get changes to

$seen[0] = 2 14 14
$seen[1] = 2
$seen[2] = 2 2 2

Presumably the (?!) is causing it to carry on trying, so it re-runs
those bits of code after @- has some entries.

Try something more like (completely untested):

my @pats = qw/abc pqr xyx/;
my %seen;
my $re = join '|', map {
qr/(\Q$_\E) (?{ $seen{$_} = 1 }) (?!)/x
} @pats;

'__pqr__xyz__pqr__abc__' =~ /$re/;

$, = $\ = "\n"
print keys %seen;
P.S. Unrelated regexp question: if I have a string or regexp in
a variable $x, and I want to use this variable to write a regexp
corresponding to 5 repeats of the contents of $x, how do I write
it? If I wrote /$x{5}/, it would be interpreted by perl as attempting
to access the value corresponding to key '5' in the hash %x.

Try /(?:$x){5}/.

Ben
 
J

J Krugman

Quoth J Krugman said:
In an attempt to find a single regexp that would succeed if three
different sub-regexps matched in any order (see why in the thread
called '"Commutative" regexps'), I started playing with (?{...})-type
regexps. As warm-up, I tried this:

1 use strict;
2 use re 'eval';
3
4 my @re0 = qw(abc pqr xyz);
5 my @seen = (undef) x @re0;
6 my @re = map sprintf('%s(?{ $seen[%d] ||= "@-" })',
7 $re0[$_], $_),
8 0..$#re0;
@- only contains entries for () sub-expressions. You have none here
(that have matched yet), so it won't work. (My guess is that the first
entry isn't filled in until after the match has finished, but I don't
rightly know...)

I get the same results (i.e. %seen never gets initialized) if I
change line 6 to

6 my @re = map sprintf('(%s)(?{ $seen[%d] ||= "@-" })',


Try something more like (completely untested):
my @pats = qw/abc pqr xyx/;
my %seen;
my $re = join '|', map {
qr/(\Q$_\E) (?{ $seen{$_} = 1 }) (?!)/x
} @pats;
'__pqr__xyz__pqr__abc__' =~ /$re/;
$, = $\ = "\n"
print keys %seen;

OK, tried it (and many variants); no luck. I now think that ?{
.... } is not the way to go; too complicated (and/or buggy) for me.


Try /(?:$x){5}/.

Thanks!

jill
 
M

Matt Garrish

J Krugman said:
In an attempt to find a single regexp that would succeed if three
different sub-regexps matched in any order (see why in the thread
called '"Commutative" regexps'), I started playing with (?{...})-type
regexps. As warm-up, I tried this:

1 use strict;
2 use re 'eval';
3
4 my @re0 = qw(abc pqr xyz);
5 my @seen = (undef) x @re0;
6 my @re = map sprintf('%s(?{ $seen[%d] ||= "@-" })',

I think you want ?? not ?

my @re = map sprintf('%s(??{ $seen[%d] ||= "@-" })',

7 $re0[$_], $_),
8 0..$#re0;
9 my $re = eval "qr/@{[join('|', @re)]}/";
10
11 #0 1 2
12 #01234567890123456789012345
13 '__pqr____xyz__pqr___abc___' =~ /(($re).*?)*/;
14
15 print "\$seen[$_] = $seen[$_]\n" for (0..$#seen);
16
17 __END__

The output then becomes

$seen[0] = 20
$seen[1] = 2
$seen[2] = 9

Matt
 
M

Matt Garrish

Matt Garrish said:
J Krugman said:
In an attempt to find a single regexp that would succeed if three
different sub-regexps matched in any order (see why in the thread
called '"Commutative" regexps'), I started playing with (?{...})-type
regexps. As warm-up, I tried this:

1 use strict;
2 use re 'eval';
3
4 my @re0 = qw(abc pqr xyz);
5 my @seen = (undef) x @re0;
6 my @re = map sprintf('%s(?{ $seen[%d] ||= "@-" })',

I think you want ?? not ?

my @re = map sprintf('%s(??{ $seen[%d] ||= "@-" })',

7 $re0[$_], $_),
8 0..$#re0;
9 my $re = eval "qr/@{[join('|', @re)]}/";
10
11 #0 1 2
12 #01234567890123456789012345
13 '__pqr____xyz__pqr___abc___' =~ /(($re).*?)*/;
14
15 print "\$seen[$_] = $seen[$_]\n" for (0..$#seen);
16
17 __END__

The output then becomes

$seen[0] = 20
$seen[1] = 2
$seen[2] = 9

Forgot to mention that I also changed line 13 to:

'__pqr____xyz__pqr___abc___' =~ /(($re).*?)*(?!)/;

as per your original post.

Matt
 

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,540
Members
45,025
Latest member
KetoRushACVFitness

Latest Threads

Top