Как переопределить \s, чтобы соответствовать подчеркиваниям?


Perl (\s для пробельных символов совпадает с [\t\n\f\r ].

Теперь, поскольку некоторые имена файлов используют подчеркивание в качестве пробелов, мне было интересно, можно ли переопределить \s (локально), чтобы соответствовать подчеркиванию в дополнение к пробелам.

Это было бы просто ради удобства чтения в противном случае запутанных регулярных выражений, имеющих много [\s_]. Могу я это сделать? Если да, то как?

1   6  

1 ответ:

Всякий раз, когда я думаю, что что-то невозможно в Perl, обычно оказывается, что я ошибаюсь. И иногда, когда я думаю, что что-то очень трудно в Perl, я тоже ошибаюсь. @sln указал мне на правильный путь

Давайте пока не будем переопределять \s, хотя могли бы. Для наследников вашей программы, которые ожидают, что \s будет означать что-то конкретное, вместо этого давайте определим последовательность \_ как "любой символ пробела или символ _" внутри a регулярное выражение. Подробности приведены в ссылке выше, но реализация выглядит следующим образом:

package myspace;  # redefine  \_  to mean  [\s_]
use overload;
my %rules = ('\\' => '\\\\', '_' => qr/[\t\n\x{0B}\f\r _]/ );
sub import {
    die if @_ > 1;
    overload::constant 'qr' => sub {
        my $re = shift;
        $re =~ s{\\(\\|_)}{$rules{$1}}gse;
        return $re;
    };
}
1;

Теперь в вашем сценарии скажите

use myspace;

А теперь \_ в регулярном выражении означает [\s_].

Демо:

use myspace;
while (<DATA>) {
    chomp;
    if ($_ =~ /aaa\s.*txt/) {      # match whitespace
        print "match[1]: $_\n";
    }
    if ($_ =~ /aaa\_.*txt/) {      # match [\s_]
        print "match[2]: $_\n";
    }
    if ($_ =~ /\\_/) {             # match literal  '\_'
        print "match[3]: $_\n";
    }
}
__DATA__
aaabbb.txt
aaa\_ccc.txt
cccaaa bbb.txt
aaa_bbb.txt

Вывод:

match[3]: aaa\_ccc.txt
match[1]: cccaaa bbb.txt
match[2]: cccaaa bbb.txt
match[2]: aaa_bbb.txt
Третий случай-продемонстрировать, что \\_ в регулярном выражении будет соответствовать литералу \_, Как \\s будет соответствовать литералу \s.