Question

I would like to find out if a file has a particular file extension, selected in a list of extensions.

I had this initial idea:

my $file = "filename.zip";
my @allowedExts = ( '.zip', '.tar.gz', '.tar.bz2' );

my $found = 0;
foreach $ext (@allowedExts) {
  if (index($file, $ext) != -1) {
    $found = 1;
    last;
  }
}

print "found" if ($found);

Is there a simpler way to do that?

Was it helpful?

Solution 2

index is not a good idea here, you might get very unexpected behaviour if the extension itself is found somewhere in the middle of filename.

Also: ALWAYS use strict and use warnings

Regex matching at the end of the string will be a better solution here, see the code below. $ is a metacharacter used to match the end of the line (or before newline at the end)

#!/usr/bin/perl                                                                                                                                                                                                                                              
use strict;
use warnings;

my $file = "filename.zip";
my @allowedExts = ( '.zip', '.tar.gz', '.tar.bz2' );

my $found = 0;
foreach my $ext (@allowedExts) {
    if ($file =~ /\Q$ext\E$/) {
        $found = 1;
        last;
    }
}

print "found" if ($found);

You will probably get loads of other ideas for solving this. As always with perl: TIMTOWTDI.

EDIT: As @ikegami suggested, regex should be escaped so that the dot is not treated as metacharacter but literal match, \Q and \E escape metacharacters in the regex.

OTHER TIPS

If you truly have many extensions (not just three), avoid the loop by finding the extension first, then checking a hash:

my $file = "filename.zip";
my @allowedExts = ( '.zip', '.tar.gz', '.tar.bz2' );

my %allowedExts;
@allowedExts{@allowedExts} = ();
my (undef, $ext) = split /(?=\.)/, $file, 2;

my $found = $ext && exists $allowedExts{$ext};

The above will treat everything in the filename starting from the first .; if you have . in the filename before what you want to find as an extension, you can assemble all the extensions into a single regex:

my $file = "filename.zip";
my @allowedExts = ( '.zip', '.tar.gz', '.tar.bz2' );

my $found = $filename =~ ( join( '|', map quotemeta, @allowedExts ) . '\z' );
use List::Util qw(first);

my $file = "filename.zip";
my @allowedExts = map qr/\Q$_$/, ( '.zip', '.tar.gz', '.tar.bz2' );

my $found = first { $file =~ /$_/ } @allowedExts;

Anther approach is to use regular expressions.

Build the regex:

my @allowedExts = qw( .zip .tar.gz .tar.bz2 );
my $pat = join '|', map quotemeta, @allowedExts;
my $re  = qr/$pat\z/;

Use it:

my $file = "filename.zip";
print "Found\n" if $file =~ $re;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top