如何动态构建Perl正则表达式?

Dr.*_*ust 8 regex perl configuration

我有一个Perl脚本,它使用File :: Next :: files遍历目录层次结构.它只会返回以".avi",".flv",".mp3",".mp4"和".wmv"结尾的脚本文件.它还将跳过以下子目录:".snvn"和以".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$/
}
Run Code Online (Sandbox Code Playgroud)

我想要做的是将允许的文件扩展名和不允许的子目录名放在配置文件中,以便可以即时更新它们.

我想知道的是如何根据配置文件中的参数编写子程序来构建正则表达式结构?

/.(avi|flv|mp3|mp4|wmv)$/

$File::Next::dir !~ /.frames$|^.svn$/
Run Code Online (Sandbox Code Playgroud)

Mic*_*man 26

假设您已经解析了配置文件以获取扩展和忽略目录的列表,您可以将正则表达式构建为字符串,然后使用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
}
Run Code Online (Sandbox Code Playgroud)

汇编不是绝对必要的; 你可以直接使用字符串模式:

if ($file =~ /$pattern/) {
    # do something
}
Run Code Online (Sandbox Code Playgroud)

目录有点难,因为你有两种不同的情况:全名和后缀.您的配置文件必须使用不同的密钥才能清楚说明哪个是哪个.例如"dir_name"和"dir_suffix".对于全名,我只是构建一个哈希:

%ignore = ('.svn' => 1);
Run Code Online (Sandbox Code Playgroud)

后缀目录可以与文件扩展名相同:

my $dir_pattern = '(?:' . join('|', map {quotemeta} @dir_suffix), ')$';
my $dir_regex   = qr/$dir_pattern/;
Run Code Online (Sandbox Code Playgroud)

您甚至可以将模式构建为匿名子例程,以避免引用全局变量:

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);
Run Code Online (Sandbox Code Playgroud)