У меня есть это регулярное выражение:
if($string =~ m/^(Clinton|[^Bush]|Reagan)/i)
{print "$string\n"};
Я хочу сочетаться с Клинтоном и Рейганом, но не с Бушем.
Не работает.
У меня есть это регулярное выражение:
if($string =~ m/^(Clinton|[^Bush]|Reagan)/i)
{print "$string\n"};
Я хочу сочетаться с Клинтоном и Рейганом, но не с Бушем.
Не работает.
Пример текста:
Клинтон сказал
Буш использовал карандаши
Рейган забыл
Просто опуская матч в Буше:
$ perl -ne 'print if /^(Clinton|Reagan)/' textfile
Clinton said
Reagan forgot
Или, если вы действительно хотите указать:
$ perl -ne 'print if /^(?!Bush)(Clinton|Reagan)/' textfile
Clinton said
Reagan forgot
Ваше регулярное выражение не работает, потому что [] определяет класс символов, но то, что вы хотите, - это просмотр:
(?=) - Positive look ahead assertion foo(?=bar) matches foo when followed by bar
(?!) - Negative look ahead assertion foo(?!bar) matches foo when not followed by bar
(?<=) - Positive look behind assertion (?<=foo)bar matches bar when preceded by foo
(?<!) - Negative look behind assertion (?<!foo)bar matches bar when NOT preceded by foo
(?>) - Once-only subpatterns (?>\d+)bar Performance enhancing when bar not present
(?(x)) - Conditional subpatterns
(?(3)foo|fu)bar - Matches foo if 3rd subpattern has matched, fu if not
(?#) - Comment (?# Pattern does x y or z)
Итак, попробуйте: (?! bush)
Ваше регулярное выражение говорит следующее:
/^ - if the line starts with
( - start a capture group
Clinton| - "Clinton"
| - or
[^Bush] - Any single character except "B", "u", "s" or "h"
| - or
Reagan) - "Reagan". End capture group.
/i - Make matches case-insensitive
Итак, другими словами, ваша средняя часть регулярного выражения закручивает вас. Поскольку это группа "всех видов", она позволит любой строке, которая не начинается с любых букв верхнего или нижнего регистра в "Буше". Например, эти строки будут соответствовать вашему регулярному выражению:
Our president, George Bush
In the news today, pigs can fly
012-3123 33
Вы либо делаете негативный прогноз вперед, как предлагалось ранее, либо просто создаете два регулярных выражения:
if( ($string =~ m/^(Clinton|Reagan)/i) and
($string !~ m/^Bush/i) ) {
print "$string\n";
}
Как отмечалось в комментариях mirod, вторая проверка совершенно не нужна при использовании каретки (^
) для соответствия только началу строк, поскольку линии, начинающиеся с "Клинтона" или "Рейгана", никогда не могут начинаться с "Буша".
Однако это было бы справедливо без кареток.
Что случилось с использованием двух регулярных выражений (или трех)? Это делает ваши намерения более ясными и может даже улучшить вашу производительность:
if ($string =~ /^(Clinton|Reagan)/i && $string !~ /Bush/i) { ... }
if (($string =~ /^Clinton/i || $string =~ /^Reagan/i)
&& $string !~ /Bush/i) {
print "$string\n"
}
Если мое понимание правильное, вы хотите соответствовать любой строке, в которой есть Клинтон и Рейган, в любом порядке, но не в Буше. Как было предложено Stuck, вот версия с прогнозными утверждениями:
#!/usr/bin/perl
use strict;
use warnings;
my $regex = qr/
(?=.*clinton)
(?!.*bush)
.*reagan
/ix;
while (<DATA>) {
chomp;
next unless (/$regex/);
print $_, "\n";
}
__DATA__
shouldn't match - reagan came first, then clinton, finally bush
first match - first two: reagan and clinton
second match - first two reverse: clinton and reagan
shouldn't match - last two: clinton and bush
shouldn't match - reverse: bush and clinton
shouldn't match - and then came obama, along comes mary
shouldn't match - to clinton with perl
Результаты
first match - first two: reagan and clinton
second match - first two reverse: clinton and reagan
по желанию, он соответствует любой строке, в которой есть Рейган и Клинтон в любом порядке.
Возможно, вам захочется попробовать прочитать, как выглядящие утверждения работают с примерами в http://www252.pair.com/comdog/mastering_perl/Chapters/02.advanced_regular_expressions.html
они очень вкусные:)