我有一个使用File::Next::files遍历目录层次结构的Perl脚本。它只会返回以“.avi”,“。flv”,“。mp3”,“。mp4”和“.wmv”结尾的脚本文件。此外,它将跳过以下子目录:“.svn”和任何以“.frames”结尾的子目录。这在下面的file_filterdescend_filter子例程中指定。

my $iter = File::Next::files(
        { file_filter => \&file_filter, descend_filter => \&descend_filter },
        $directory );

sub file_filter {
    # Called from File::Next:files.
    # Only select video files that end with the following extensions.
    /.(avi|flv|mp3|mp4|wmv)$/
}

sub descend_filter {
    # Called from File::Next:files.
    # Skip subfolders that either end in ".frames" or are named the following:
    $File::Next::dir !~ /.frames$|^.svn$/
}

我想做的是将允许的文件扩展名和不允许的子目录名称放在配置文件中,以便可以随时对其进行更新。

我想知道的是如何根据配置文件中的参数对子例程进行编码以构建正则表达式构造?
/.(avi|flv|mp3|mp4|wmv)$/

$File::Next::dir !~ /.frames$|^.svn$/

最佳答案

假设您已解析配置文件以获取扩展名列表和忽略的目录,则可以将正则表达式构建为字符串,然后使用qr运算符将其编译为正则表达式:

my @extensions = qw(avi flv mp3 mp4 wmv);  # parsed from file
my $pattern    = '\.(' . join('|', @wanted) . ')$';
my $regex      = qr/$pattern/;

if ($file =~ $regex) {
    # do something
}

编译不是严格必需的。您可以直接使用字符串模式:
if ($file =~ /$pattern/) {
    # do something
}

目录要难一些,因为您有两种不同的情况:全名和后缀。您的配置文件将必须使用不同的键来明确显示哪个。例如“dir_name”和“dir_suffix”。对于全名,我只是构建一个哈希:
%ignore = ('.svn' => 1);

后缀目录可以使用与文件扩展名相同的方式来完成:
my $dir_pattern = '(?:' . join('|', map {quotemeta} @dir_suffix), ')$';
my $dir_regex   = qr/$dir_pattern/;

您甚至可以将模式构建到匿名子例程中,以避免引用全局变量:
my $file_filter    = sub { $_ =~ $regex };
my $descend_filter = sub {
    ! $ignore{$File::Next::dir} &&
    ! $File::Next::dir =~ $dir_regex;
};

my $iter = File::Next::files({
    file_filter    => $file_filter,
    descend_filter => $descend_filter,
}, $directory);

10-07 13:16
查看更多