Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What to use instead of Smartmatch?

Tags:

regex

perl

I just upgraded to Perl 5.26.1, now I get

Smartmatch is experimental at check_tr.pl line 67.

where the code in question is

my @patterns = (qr/summary:\s+(.+?) in\s+(.+?) - average of\s+(.+?)$/,
        qr/summary:\s+(.+?) in\s+(.+) (.+? .+?)$/);
my $r = "";
opendir(DIR, $dir) or die $!;
while(my $file = readdir(DIR)) {

    next if ($file =~ m/^\./);
     open(F, '<', "$dir/$file") or die $!;

     if (<F> ~~ @patterns) {
         $r .= <F>;
...

Question

Ideally with as few changes to the code as possible. What should I do instead of smart matching?

like image 559
Sandra Schlichting Avatar asked Apr 19 '18 12:04

Sandra Schlichting


2 Answers

Just spell out what you mean. E.g. if you want to check whether the header line matches any regex in @patterns:

use List::Util 'any';
...
my $line = <F>;
if (any { $line =~ $_ } @patterns) { ... }

Though in that case, it might be more sensible to pre-compile a single pattern such as:

my ($pattern) = map qr/$_/, join '|', @patterns;
...
if (<F> =~ $pattern) { ... }

If your @patterns array contains different kinds of data, you might want to choose a different matching operator, e.g. == or eq. If the @patterns are not all the same “type” and you really want the smartmatch behaviour, you can silence the warning and continue to use it:

use experimental 'smartmatch';

However, this might then break without further warnings in the future.

like image 176
amon Avatar answered Sep 20 '22 01:09

amon


The reason Smartmatch is experimental is that it is so hard to figure out what it will do without referencing the Docs. Even so, how do we interperet the above code?

Is this a case of:

ARRAY1    ARRAY2     recurse on paired elements of ARRAY1 and ARRAY2[2]
            like: (ARRAY1[0] ~~ ARRAY2[0])
                    && (ARRAY1[1] ~~ ARRAY2[1]) && ...

Where we presume <F> is interpreted in list context and emptied in a single call?

Or is this a case of:

 Any       ARRAY      smartmatch each ARRAY element[3]
            like: grep { Any ~~ $_ } ARRAY

I'm going to guess the 2nd. In which case the snippet above from the docs gives you an excellent (and clearer) coding alternative. Presuming @patterns contains regexes, you can also replace the ~~ with =~.


If you don't like the grep alternative from the docs, I'd recommend looking into either List::Util or List::MoreUtils. Both contain an any call which acts as a short-circuiting grep. Alternatively, if you are trying to implement the ARRAY1 ARRAY2 option, the later library contains a pairwise call that may serve.

like image 45
tjd Avatar answered Sep 24 '22 01:09

tjd