2015-07-13 3 views
6

Perl (< v5.18) регулярное выражение класс символов \s для пробелов - это то же самое, что и [\t\n\f\r ].Как переопределить s для соответствия символам подчеркивания?

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

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

+1

Храните регулярное выражение в переменной с помощью 'qr' – toolic

+14

IMHO, изменяя значение \ s, чтобы тихо вести себя нестандартным способом, может ухудшить читаемость, а не улучшать ее. Даже если вы четко документируете это в комментариях, это требует, чтобы кто-нибудь читал ваш код, чтобы помнить, что каждый раз, когда они видят \ s, они должны мысленно заменить его на [\ s_]. – plasticinsect

+6

'$ s = qr/[\ s _] /;' – ikegami

ответ

12

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

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

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.

+2

. В настоящее время никто не использует myspace ... :) – simbabque