2012-05-16 3 views
2

Я хочу, чтобы регулярное выражение соответствовало всем, кроме нескольких конкретных вариантов в более широком выражении.Против (foo | bar | baz)

Следующий пример будет соответствовать test_foo.pl или test_bar.pl или test_baz.pl:

/test_(foo|bar|baz)\.pl/ 

Но я хотел бы как раз наоборот:

match test_.*\.pl except for where .* = (foo|bar|baz) 

Я отчасти ограничен в моих вариантах для этого, потому что это не напрямую в perl-программу, а аргумент cloc, a program that counts lines of code (that happens to be written in perl). Поэтому я ищу ответ, который можно сделать в одном регулярном выражении, а не в нескольких цепях.

ответ

6

Вы должны быть в состоянии сделать это с помощью отрицательного предпросмотра:

/test_(?!foo|bar|baz).*\.pl/ 

Это не сработает, если foo, bar или baztest_ непосредственно следует.

Обратите внимание, что это все равно может совпадать с чем-то вроде test_notfoo.pl и не получится на test_fool.pl, если вы не хотите этого поведения, проясните, добавив несколько примеров того, что именно должно и должно не совпадать.

Если вы хотите принять что-то вроде test_fool.pl или test_bart.pl, то вы можете изменить его на следующее:

/test_(?!(foo|bar|baz)\.pl).*\.pl/ 
+0

бить меня по секундам. +1 –

+0

Я думаю, что ваш soution отклонит 'test_bart.pl', но, как я понял, OP примет' test_bart.pl', но не 'test_bar.pl' (просто пример, отметив, что особый, связанный с' bart') – ArtM

+0

Чтобы сделать это * только * исключить givens, вам нужно также совместить конец выражения: '/ test _ (?! (Foo | bar | baz) \. Pl). * \. Pl /'. (Эта версия также неверна, если строка содержит несколько имен файлов (из-за '. *'), Но это не должно быть в контексте вопроса.) – porges

0

Хм, я бы понял ваш вопрос. В любом случае, может быть, это полезно ...


Вы бы отказали оператору матча. Например:

perl -lwe "print for grep ! m/(lwp|archive).*\.pl/, glob q(*.pl)" 
# Note you'd use single-quotes on Linux but double-quotes on Windows. 
# Nothing to do with Perl, just different shells (bash vs cmd.exe). 

! отменяет игру. Выше является сокращением для:

perl -lwe "print for grep ! ($_ =~ m/(lwp|archive).*\.pl/), glob q(*.pl)" 

, которые также могут быть записаны с помощью отрицания оператора совпадения !~ следующим образом:

perl -lwe "print for grep $_ !~ m/(lwp|archive).*\.pl/, glob q(*.pl)" 

В случае, если вам интересно, то glob просто используется, чтобы получить введите список имен файлов в соответствии с вашим примером. Я просто заменил другой шаблон соответствия, подходящий для файлов, которые мне были удобны в каталоге.

1
#!/usr/bin/env perl 

use strict; use warnings; 

my $pat = qr/\Atest_.+(?<!foo|bar|baz)[.]pl\z/; 

while (my $line = <DATA>) { 
    chomp $line; 
    printf "%s %s\n", $line, $line =~ $pat ? 'matches' : "doesn't match"; 
} 


__DATA__ 
test_bar.pl 
test_foo.pl 
test_baz.pl 
test baz.pl 
0test_bar.pl 
test_me.pl 
test_me_too.txt 

Выход:

test_bar.pl doesn't match 
test_foo.pl doesn't match 
test_baz.pl doesn't match 
test baz.pl doesn't match 
0test_bar.pl doesn't match 
test_me.pl matches 
test_me_too.txt doesn't match

1
(?:(?!STR).)* 

является

STR 

в

[^CHAR] 

является

CHAR 

Так что вы хотите

if (/^test_(?:(?!foo|bar|baz).)*\.pl\z/s) 

Более читаемый:

my %bad = map { $_ => 1 } qw(foo bar baz); 

if (/^test_(.*)\.pl\z/s && !$bad{$1}) 
Смежные вопросы