5

Is there a way I can avoid using this for multiple pattern checks?

Can I tore all the patterns in an array and check if it matches any pattern in the pattern array? Please consider the case when I have more than 20 pattern strings.

if(  ($_=~ /.*\.so$/)
  || ($_=~ /.*_mdb\.v$/)
  || ($_=~ /.*daidir/)
  || ($_=~ /\.__solver_cache__/)
  || ($_=~ /csrc/)
  || ($_=~ /csrc\.vmc/)
  || ($_=~ /gensimv/)
){
  ...
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Arovit
  • 3,579
  • 5
  • 20
  • 24

3 Answers3

11

If you can use Perl version 5.10, then there is a really easy way to do that. Just use the new smart match (~~) operator.

use warnings;
use strict;
use 5.10.1;

my @matches = (
  qr/.*\.so$/,
  qr/.*_mdb\.v$/,
  qr/.*daidir/,
  qr/\.__solver_cache__/,
  qr/csrc/,
  qr/csrc\.vmc/,
  qr/gensimv/,
);

if( $_ ~~ @matches ){
  ...
}

If you can't use Perl 5.10, then I would use List::MoreUtils::any.

use warnings;
use strict;
use List::MoreUtils qw'any';

my @matches = (
  # same as above
);

my $test = $_; # copy to a named variable

if( any { $test =~ $_ } @matches ){
  ...
}
Brad Gilbert
  • 33,846
  • 11
  • 78
  • 129
  • 1
    Note that smartmatch is now flagged as experimental, and it *will* be removed or changed without further notice. (Sounds like this will happen in 5.26.) The latter solution should be used regardless of your version of Perl. – ikegami Sep 08 '16 at 15:35
4

Another pre-Perl 5.10 option is Regexp::Assemble, which will take a list of patterns and combine them into a single regex that will test all of the original conditions at once.

Dave Sherohman
  • 45,363
  • 14
  • 64
  • 102
  • This can be far more efficient, especially if the pattern is tested is against multiple values. Starting a regex match is actually fairly expensive. – ikegami Sep 08 '16 at 15:37
1

Your original code could have been written more nicely like this:

if(  /.*\.so$/
  || /.*_mdb\.v$/
  || /.*daidir/
  || /\.__solver_cache__/
  || /csrc/
  || /csrc\.vmc/
  || /gensimv/
) { ... }

That is because $_ =~ /foo/ is the same as just /foo/. If you have Perl 5.10 or greater, I would do as Brad suggested and use the smart match operator.

serenesat
  • 4,611
  • 10
  • 37
  • 53
Naveed
  • 726
  • 1
  • 5
  • 12