On Jan 17, 2016, at 11:07 AM, Tom Browder <[email protected]> wrote:
> I'm trying to write all new Perl code in Perl 6. One thing I need is
> the equivalent of the Perl 5 qr// and, following Perl 6 docs, I've
> come to use something like this (I'm trying to ignore certain
> directories):
>
> # regex of dirs to ignore
> my regex dirs {
> \/home\/user\/\.cpan |
> \/home\/tbrowde\/\.emacs
> }
>
> for "dirlist.txt".IO.lines -> $line {
> # ignore certain dirs
> if $line ~~ m{<dirs>} {
> next;
> }
> }
>
> My question: Is there a way to have Perl 6 do the required escaping
> for the regex programmatically, i.e., turn this:
>
> my $str = '/home/usr/.cpan';
>
> into this:
>
> my regex dirs {
> \/home\/usr\/\.cpan
> }
>
> automatically?
I think that your regex needs anchors to do what you want;
your current regex will also exclude `/home/user/.cpanabcedfg`, for example.
This is how I do it in Perl 5 (when using regexes instead of a hash):
my $dirs = join '|', map { quotemeta } qw(
/home/user/.cpan
/home/tbrowde/.emacs
);
my $dirs_re = qr/^(?:$dirs)$/;
So, `quotemeta` is what you are looking for.
Except that https://design.perl6.org/S29.html#Obsolete_Functions says:
quotemeta
Because regex escaping metacharacters can easily be solved by quotes
("Simplified lexical parsing of patterns" in S05),
and variables are not automatically interpolated
("Variable (non-)interpolation" in S05),
quotemeta is no longer needed.
http://design.perl6.org/S05.html#Simplified_lexical_parsing_of_patterns
http://design.perl6.org/S05.html#Variable_%28non-%29interpolation
Summary of `Variable_%28non-%29interpolation`:
In Perl 5, /$var/ deposits the contents of `$var` into the regex,
just like of you had typed them in the source code.
In Perl 6, /$var/ runs quotemeta on the contents of `$var`.
If you want the Perl 5 behavior, then you write it as /<$var>/.
Also, if you embed an array in a regex, it automatically treats it as `|`
alternatives.
So cool!
# Plain text, *not* regex!
my @dirs_to_skip = <
/home/user/.cpan
/home/tbrowde/.emacs
> ;
...
next if $line ~~ / ^ @dirs_to_skip $ /;
Or, precompiled:
my @dirs_to_skip = <
/home/user/.cpan
/home/tbrowde/.emacs
> ;
my $dir_re = / ^ @dirs_to_skip $ /;
...
next if $line ~~ $dir_re;
If you know that your exclusion list is always literal,
you can leave the regex engine out of the process,
and just do a hash lookup
(which is even easier in Perl 6 with `set`, which sets the values all to
`True`):
my %dirs_to_skip = set <
/home/user/.cpan
/home/tbrowde/.emacs
> ;
...
next if %dirs_to_skip{$line};
--
Hope this helps,
Bruce Gray (Util of PerlMonks)