Либо преобразуйте glob в регулярное выражение, либо используйте Perl для обработки шаблонов glob.

У меня есть файл конфигурации .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;
}

person David W.    schedule 07.07.2011    source источник
comment
Существует search.cpan.org/perldoc?Text::Glob и search.cpan.org/perldoc?File::Glob. В первом случае сопоставление с регулярными выражениями выполняется в виде шара, а во втором реализуется сопоставление в виде шара для файловой системы.   -  person DavidO    schedule 08.07.2011
comment
Я надеялся на какой-нибудь хитрый трюк, о котором знают гуру Perl (например, возможность интерполировать функции в строках в кавычках с помощью синтаксиса @{[function]}), которого не знают простые смертные и мы, второсортные программисты. Я видел Text::Glob, но он все равно не расширяет расширенные глобусы в стиле Ant.   -  person David W.    schedule 08.07.2011
comment
Не могли бы вы указать четкое определение расширения glob в стиле Ant? Возможно, точка отсчета поможет найти решение.   -  person DavidO    schedule 08.07.2011
comment
В Руководстве Ant   -  person David W.    schedule 10.07.2011


Ответы (2)


Учитывая это:

  1. ? соответствует только одному символу, кроме '/'
  2. * соответствует нулю или более символов, кроме '/'
  3. ** соответствует чему угодно, включая /

Если вы не заботитесь о проверке формата и некоторых крайних случаях, таких как «***», то может работать следующая стратегия, в которой вы сначала конвертируете специальные символы в специально разработанные escape-последовательности, а затем конвертируете escape-последовательности в окончательные строки. :

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;
}
person Ding-Yi Chen    schedule 12.02.2013

Судя по всему, нет изящного приема Perl Guru для создания регулярного выражения из глобуса. Дратс.

Лучшее, что я могу сделать, это найти модуль CPAN, например Text ::Glob, который делает это. Однако Text::Glob не выполняет расширенную подстановку в стиле Ant, поэтому я бы все равно модифицировать. И код не проще того, что у меня уже есть.

Так что я просто придерживаюсь того, что у меня есть.

Спасибо, в любом случае.

person David W.    schedule 05.08.2011