Re: interpolating the return from embedded code in a regexp

2020-06-15 Thread yary
Brad: "Note that {} is there to update $/ so that $0 works the way you
would expect"

I ran into that before & was trying to remember that detail... found it in
https://docs.raku.org/language/regexes#Capture_numbers

But the example is a bit on the obtuse side:

These capture variables are only available outside the regex.

# !!WRONG!! The $0 refers to a capture *inside* the second capture
say "11" ~~ /(\d) ($0)/; # OUTPUT: «Nil␤»

In order to make them available inside the regex, you need to insert a code
block behind the match; this code block may be empty if there's nothing
meaningful to do:

# CORRECT: $0 is saved into a variable outside the second capture
# before it is used inside
say "11" ~~ /(\d) {} :my $c = $0; ($c)/; # OUTPUT: «「11」␤ 0 => 「1」␤ 1 => 「1」␤»
say "Matched $c"; # OUTPUT: «␤Matched 1␤»


As of Raku 2019.11 at least, the $0 construct works without the {} code
block, in simple cases.

> "11" ~~ /(\d) $0/

「11」

 0 => 「1」

> '876554' ~~ /(\d) $0/

「55」

 0 => 「5」


# Inside a new capture, $0 refers to inner capture

> "11" ~~ /(\d) ($0)/

Nil

> "11" ~~ /(\d) {} ($0)/

Nil

> "11" ~~ /(\d) {} :my $c=$0; ($c)/

「11」

 0 => 「1」

 1 => 「1」
# Let's use that inner capture

> "1122" ~~ /(\d) {} :my $c=$0; ($c (\d) $0)/

「1122」

 0 => 「1」

 1 => 「122」

  0 => 「2」

The Match docs can be clearer on when to use {} and when it isn't needed,
opened an issue https://github.com/Raku/doc/issues/3478

-y


On Mon, Jun 15, 2020 at 3:09 PM Brad Gilbert  wrote:

> You don't want to use <{…}>, you want to use ""
>
> if $line ~~ / (^P\d+) \s+ {} "%products{$0}" / {
>
> Note that {} is there to update $/ so that $0 works the way you would
> expect
>
> Although I would do something like this instead:
>
> my ($code,$desc) = $line.split( /\s+/, 2 );
> if %products{$code} eq $desc {
>
> On Sun, Jun 14, 2020 at 6:44 PM Joseph Brenner  wrote:
>
>> In part because of the recent discussion here, I decided to
>> play around with using Raku code embedded in a regexp.
>> I came up with a contrived example where I was going to
>> examine a product listing in a text block to see if the product
>> descriptions matched the product codes.  The valid associations
>> I have in a hash, so I'm (1) matching for product codes; (2)
>> using embedded code to look-up the associated description in the hash;
>> (3) using the returned description inside the regex.
>>
>> my %products = ( 'P123' => "Green Labels That Say Magenta",
>>  'P666' => 'Darkseid For President Bumpersticker',
>>  'P912' => "Corn dogs",
>>  );
>>
>> my $text =  q:to/END/;
>> P123  Viridian Green Label Saying Magenta
>> P666  Yoda puppets
>> P912  Corn dogs
>> END
>>
>> my @lines = $text.lines;
>> say @lines;
>>
>> for @lines -> $line {
>>say "checking line: $line";
>>## This line works, but it's not a complete solution:
>>if $line ~~ / (^P\d+) \s+ <{ %products{$0}.subst(/\s+/, '\s', :g) }> /
>> {
>>say "Matched, line looks good";
>>}
>>else {
>>say "NO: bad line.";
>>}
>> }
>>
>> I'd thought that a line like this would work:
>>
>> if $line ~~ / (^P\d+) \s+ <{ %products{$0} }> / {
>>
>> The trouble though is I've got spaces inside the descriptions,
>> so if the returned string is treated as a regexp, I get these
>> warnings:
>>
>>Potential difficulties:
>>Space is not significant here; please use quotes or :s
>> (:sigspace) modifier (or, to suppress this warning, omit the space, or
>> otherwise change the spacing)
>>
>> Reading a bit, I thought this should work
>>
>> if $line ~~ / (^P\d+) \s+ $( %products{$0} ) / {
>>
>> That's supposed to use the return string as a literal match.
>> Instead I get a lot of strange messages like:
>>
>>Use of Nil in string context   in regex
>>
>> Flailing around I considered lots of variations like this:
>>
>>if $line ~~ / (^P\d+) \s+ Q[<{ %products{$0}}>] / {
>>
>> But I think that ends up treating everything inside the Q[]
>> literally, so you never do the hash lookup.
>>
>> Another thing that might solve this problem is some sort of
>> regexp quote function I could use inside the code before
>> returning the string, but I don't know what that would be...
>>
>


Re: interpolating the return from embedded code in a regexp

2020-06-15 Thread Brad Gilbert
You don't want to use <{…}>, you want to use ""

if $line ~~ / (^P\d+) \s+ {} "%products{$0}" / {

Note that {} is there to update $/ so that $0 works the way you would expect

Although I would do something like this instead:

my ($code,$desc) = $line.split( /\s+/, 2 );
if %products{$code} eq $desc {

On Sun, Jun 14, 2020 at 6:44 PM Joseph Brenner  wrote:

> In part because of the recent discussion here, I decided to
> play around with using Raku code embedded in a regexp.
> I came up with a contrived example where I was going to
> examine a product listing in a text block to see if the product
> descriptions matched the product codes.  The valid associations
> I have in a hash, so I'm (1) matching for product codes; (2)
> using embedded code to look-up the associated description in the hash;
> (3) using the returned description inside the regex.
>
> my %products = ( 'P123' => "Green Labels That Say Magenta",
>  'P666' => 'Darkseid For President Bumpersticker',
>  'P912' => "Corn dogs",
>  );
>
> my $text =  q:to/END/;
> P123  Viridian Green Label Saying Magenta
> P666  Yoda puppets
> P912  Corn dogs
> END
>
> my @lines = $text.lines;
> say @lines;
>
> for @lines -> $line {
>say "checking line: $line";
>## This line works, but it's not a complete solution:
>if $line ~~ / (^P\d+) \s+ <{ %products{$0}.subst(/\s+/, '\s', :g) }> / {
>say "Matched, line looks good";
>}
>else {
>say "NO: bad line.";
>}
> }
>
> I'd thought that a line like this would work:
>
> if $line ~~ / (^P\d+) \s+ <{ %products{$0} }> / {
>
> The trouble though is I've got spaces inside the descriptions,
> so if the returned string is treated as a regexp, I get these
> warnings:
>
>Potential difficulties:
>Space is not significant here; please use quotes or :s
> (:sigspace) modifier (or, to suppress this warning, omit the space, or
> otherwise change the spacing)
>
> Reading a bit, I thought this should work
>
> if $line ~~ / (^P\d+) \s+ $( %products{$0} ) / {
>
> That's supposed to use the return string as a literal match.
> Instead I get a lot of strange messages like:
>
>Use of Nil in string context   in regex
>
> Flailing around I considered lots of variations like this:
>
>if $line ~~ / (^P\d+) \s+ Q[<{ %products{$0}}>] / {
>
> But I think that ends up treating everything inside the Q[]
> literally, so you never do the hash lookup.
>
> Another thing that might solve this problem is some sort of
> regexp quote function I could use inside the code before
> returning the string, but I don't know what that would be...
>