【问题标题】:Either convert a glob to regex or have Perl handle glob patterns要么将 glob 转换为正则表达式,要么让 Perl 处理 glob 模式
【发布时间】:2017-06-22 02:11:54
【问题描述】:

我有一个配置 .ini 文件,用户可以在其中使用 Perl 正则表达式或 Ant 通配模式指定文件模式。例如,以下内容将禁止用户创建 Windows 下不允许的文件:

[BAN Defined using Ant Globbing]
file = **/prn.*
ignorecase = true

[BAN Defined using Regular expressions]
match = /(aux|con|com[0-9]*|lpt[0-9]*|nul|clock$)\.?[a-z]$
ignorecase = true

现在,我必须将 glob 转换为正则表达式才能以编程方式处理它。我有一个例行程序,但它有点复杂。我正在寻找以下之一:

  • 将 glob 转换为正则表达式的简单方法
  • 使用正则表达式匹配全局表达式的方法。

例如:

 if ($regex =~ /\/(aux|con|com[0-9]*|lpt[0-9]*|nul|clock$)\.?[a-z]$) {
 if ($glob ?magic? /**/prn.*/) {

我希望有一些神奇的 Perl 方法可以做到这一点。那么,有没有一种简单的不能错过的方法:

顺便说一句,如果有人感兴趣,这是我的子程序:

sub glob2regex {
    my $glob = shift;

    my $regex = undef;
    my $previousAstrisk = undef;

    foreach my $letter (split(//, $glob)) {
        #
        #    ####Check if previous letter was astrisk
        #
        if ($previousAstrisk) {
            if ($letter eq "*") { #Double astrisk
                $regex .= ".*";
                $previousAstrisk = undef;
                next;
            } else {        #Single astrisk: Write prev match
                $regex .= "[^/]*";
                $previousAstrisk = undef;
            }
        }
        #
        #   ####Quote all Regex characters w/ no meaning in glob
        #
        if ($letter =~ /[\{\}\.\+\(\)\[\]]/) {
            $regex .= "\\$letter";
            #
            #   ####Translate "?" to Regular expression equivelent
            #
        } elsif ($letter eq "?") {
            $regex .= ".";
            #
            #   ####Don't know how to handle astrisks until  the next line
            #
        } elsif ($letter eq "*") {
            $previousAstrisk = 1;
            #
            #   ####Convert backslashes to forward slashes
            #
        } elsif ($letter eq '\\') {
            $regex .= "/";
            #
            #   ####Just a letter
            #
        } else {
            $regex .= $letter;
        }
    }
    #
    #   ####Handle if last letter was astrisk
    #
    if ($previousAstrisk) {
        $regex .= "[^/]*";
    }
    #
    #    ####Globs are anchored to both beginning and ending
    #
    $regex = "^$regex\$";
    return $regex;
}

【问题讨论】:

  • search.cpan.org/perldoc?Text::Globsearch.cpan.org/perldoc?File::Glob。前者为正则表达式提供类 glob 匹配,后者为文件系统实现类 glob 匹配。
  • 我希望有一些 Perl 大师知道的巧妙技巧(比如能够通过 @{[function]} 语法在引用的字符串中插入函数),而普通人和我们二流的编程黑客都不知道.我看到了Text::Glob,但它并没有扩展 Ant 风格的扩展 glob。
  • 您能否指出 Ant 样式 glob 扩展的可靠定义?也许一个参考点会帮助想出一个解决方案。

标签: regex perl glob


【解决方案1】:

鉴于:

  1. ?只匹配一个字符,除了 '/'
  2. * 匹配零个或多个字符,除了'/'
  3. ** 匹配任何内容,包括 /

如果你不关心格式检查和一些像“***”这样的极端情况,那么下面的策略,你首先将特殊字符转换为自定义设计的转义序列,然后将转义序列转换为最终字符串,可能会起作用:

my $rgx="^$glob\$";
$rgx=~ s|!|!e|g;
$rgx=~ s|[+]|!p|g;
$rgx=~ s|[*]{2}|!d|g;
$rgx=~ s|[*]|!s|g;
$rgx=~ s|[?]|!q|g;
$rgx=~ s|[.]|\\.|g;

$rgx=~ s|!d|.*|g;
$rgx=~ s|!s|[^/]*|g;
$rgx=~ s|!q|[^/]|g;
$rgx=~ s|!p|\\+|g;
$rgx=~ s|!e|!|g;
if ($path =~ m|$rgx|){
    return 1;
}

【讨论】:

    【解决方案2】:

    显然,从 glob 创建正则表达式并没有巧妙的 Perl Guru 技巧。德拉斯。

    我能做的最好的就是找到一个像 Text::Glob 这样的 CPAN 模块。但是,Text::Glob 不做 Ant 样式扩展通配符,所以无论如何我都必须修改它。而且,代码并不比我已有的简单。

    所以,我只是坚持我所拥有的。

    还是谢谢。

    【讨论】:

      猜你喜欢
      • 2017-04-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多