2

There are different ways to do things. What I want to do are (A) match any patterns in a Set, and (B) match all patterns in a Set in any order. E.g., if a set is (1,2,3), then (A) is true if a string contains 1, or 2, or 3; (B) is true if a string contains 1 and 2 and 3 in any order.

A while back, smls answered a question using array: perl6 Is using junctions in matching possible? (Thanks smls); but this time I want to use Set, using .one and .all if possible because using Set significantly simplifies other parts of my program.

I am using the July version of Rakudo. Here is a transcript. Thanks !!!

To exit type 'exit' or '^D'
> my $a = < one two 3 >
(one two 3)
> do "two" ~~ $a.one
True
> so 4 ~~ $a.one
False
> so "zzzonezz" ~~ $a.one
False
> my $b = "one"
one
> so "zzonezz" ~~ m/ {$b} /         # trying to interpolate into regex
True
> so "zzzonezz" ~~ m/ { $a.one } /  # trying to interpolate into regex
True
> say "zzzonezz" ~~ m/ { $a.one } /
「」                                  # empty match is True ?????
> my $c = "zzzonezz" ~~ m/ { $a.one } /
「」                                # why is the match empty and not "one"?
> so "zzonezz" ~~ m/ $b /
True
> my $c = "zzzonezz" ~~ m/ $a.one / # $b above is evaluated, 
# how come this one isn't evaluated ??
# why either /{$b}/ or /$b/ works, but only /{$a.one}/ works and
# /$a.one/ doesn't ???
False
> so "xxonetwo3xx" ~~ m/ { $a.all } /
True
> so "xxone 3 twoxx" ~~ m/ { $a.all } / # seems to work
True
> so "xxone 3 twoxx" ~~ m/  $a.all  / 
False
lisprogtor
  • 5,677
  • 11
  • 17
  • I don't think junction expansion in matches is implemented. In the cases where `.all` returns true, `.none` also returns true. That seems strong evidence it's not implemented. – piojo Sep 14 '17 at 10:50
  • Also, you can't interpolate strings into regexes with a block. I'm not sure what the rule is for how different types are incorporated into the regex (ints/ranges work in the `**` context), but strings don't seem to work at all, except within an assertion. – piojo Sep 14 '17 at 10:53

1 Answers1

2

The reason m/ {$b} / matches is the same reason m/ {False} / matches. Plain bare blocks in a regex don't (usually) affect whether it will match.

Basically m/ {} / is a null regex, it is as if you used m/ '' /.


What you want in this case is to use <{…}>

my $a = < one two 3 >;
my $b = "one";

so "zzonezz" ~~ m/ $b /; # True
so "zz   zz" ~~ m/ $b /; # False

so "zzonezz" ~~ m/ <{ $b }> /; # True
so "zz   zz" ~~ m/ <{ $b }> /; # False

In the case of $a all you need to do is to add @ to it. (or name it @a)

so "zzonezz" ~~ m/ @$a /; # True
so "zz   zz" ~~ m/ @$a /; # False

so "zzonezz" ~~ m/ <{ @$a }> /; # True
so "zz   zz" ~~ m/ <{ @$a }> /; # False

Or do something else that will un-itemize it.

so "zzonezz" ~~ m/ <{ $a.list }> /; # True
so "zz   zz" ~~ m/ <{ $a.list }> /; # False

You could also do something like this.

so "zzonezz" ~~ m/ .*? <?{ $/ ~~ $a.one }> /; # True
so "zz   zz" ~~ m/ .*? <?{ $/ ~~ $a.one }> /; # False

Note that <?{…}> is a zero width assertion that succeeds if the result is truish.
There is also <!{…}> that does the opposite.


To use a Set, currently you need to call the .keys method to get it into a list.

my $c = $a.Set;

so "zzonezz" ~~ m/ @( $c.keys ) /; # True
so "zz   zz" ~~ m/ @( $c.keys ) /; # False

so "zzonezz" ~~ m/ <{ $c.keys }> /; # True
so "zz   zz" ~~ m/ <{ $c.keys }> /; # False
Brad Gilbert
  • 33,846
  • 11
  • 78
  • 129
  • Thank you Brad Gilbert !!! Your explanation helped tremendously. I have a few more questions that are too long for a comment. So, I am posting another question. Thank !! – lisprogtor Sep 14 '17 at 22:03