Как я могу сопоставить несколько регулярных выражений в Perl?
Я хотел бы проверить, соответствует ли какая-либо строка любому заданному набору регулярных выражений. Как я могу это сделать?
Ответы
Ответ 1
Мой переход для тестирования значения сразу против нескольких регулярных выражений - Regexp::Assemble, который будет "Собрать несколько регулярных выражений в один RE", несколько более интеллектуальным и оптимизированным, чем просто join '|', @regexps
. По умолчанию вы также можете получить часть текста, который соответствует, и, если вам нужно знать, какой шаблон соответствует, коммутатор track
предоставит эту информацию. Его производительность неплохая - в одном приложении я использую его для тестирования 1700 шаблонов одновременно, и мне еще нужно что-то, чего он не делает.
Ответ 2
Используйте интеллектуальное сопоставление, если у вас есть версия версии 5.10 или новее!
#! /usr/bin/env perl
use warnings;
use strict;
use feature 'switch';
my @patterns = (
qr/foo/,
qr/bar/,
qr/baz/,
);
for (qw/ blurfl bar quux foo baz /) {
no warnings 'experimental::smartmatch';
print "$_: ";
given ($_) {
when (@patterns) {
print "hit!\n";
}
default {
print "miss.\n";
}
}
}
Хотя вы не видите явный оператор ~~
, Perl given
/when
делает это за кулисами:
Большая часть энергии исходит из неявного smartmatching, который может иногда применяться. В большинстве случаев when(EXPR)
рассматривается как неявный smartmatch $_
, то есть $_ ~~ EXPR
. (См. Оператор Smartmatch в perlop для получения дополнительной информации о smartmatching.)
"Оператор Smartmatch" в perlop дает таблицу многих комбинаций, которую вы можете использовать, а приведенный выше код соответствует случаю, когда $a
есть Any и $b
- массив, который примерно соответствует
grep $a ~~ $_, @$b
за исключением поисковых коротких замыканий, то есть быстро возвращается в соответствие, а не обрабатывает все элементы. В неявном цикле тогда были умные сопоставления Any против Regex, который
$a =~ /$b/
Вывод:
blurfl: miss.
bar: hit!
quux: miss.
foo: hit!
baz: hit!
Добавление
Поскольку этот ответ был изначально написан, дизайнеры Perls поняли, что были ошибки в способе работы smartmatching, и поэтому он теперь считается экспериментальной функцией. Случай, использованный выше, не является одним из противоречивых видов использования, тем не менее вывод кодов будет включать в себя given is experimental
и when is experimental
, за исключением того, что я добавил no warnings 'experimental::smartmatch';
.
Любое использование экспериментальных функций связано с некоторым риском, но Id оценивает это как маловероятное для этого случая. При использовании кода, подобного описанному выше, и перехода на новую версию Perl, это потенциальная информация, о которой нужно знать.
Ответ 3
От perlfaq6 ответ на Как эффективно сопоставлять многие регулярные выражения сразу?, в этом случае последняя версия разработки, которую я только что обновил с помощью примера умного соответствия.
Как эффективно сопоставить сразу несколько регулярных выражений?
(внесенный brian d foy)
Если у вас есть Perl 5.10 или новее, это почти тривиально. Ты просто умный
совпадение с массивом объектов регулярного выражения:
my @patterns = ( qr/Fr.d/, qr/B.rn.y/, qr/W.lm./ );
if( $string ~~ @patterns ) {
...
};
Умное совпадение останавливается, когда находит совпадение, поэтому ему не нужно пытаться
каждое выражение.
Ранее, чем Perl 5.10, вам нужно немного поработать. Вы хотите
избегайте компиляции регулярного выражения каждый раз, когда вы хотите его сопоставить.
В этом примере perl должен перекомпилировать регулярное выражение для каждого
итерация цикла C, поскольку она не имеет способа узнать, что
C будет:
my @patterns = qw( foo bar baz );
LINE: while( <DATA> ) {
foreach $pattern ( @patterns ) {
if( /\b$pattern\b/i ) {
print;
next LINE;
}
}
}
Оператор C появился в perl 5.005. Он собирает
выражение, но не применяет его. Когда вы используете предварительно скомпилированный
версия регулярного выражения, perl делает меньше работы. В этом примере я вставил
C, чтобы превратить каждый шаблон в его предварительно скомпилированную форму. Остальная часть
script одинаков, но быстрее:
my @patterns = map { qr/\b$_\b/i } qw( foo bar baz );
LINE: while( <> ) {
foreach $pattern ( @patterns ) {
if( /$pattern/ )
{
print;
next LINE;
}
}
}
В некоторых случаях вы можете сделать несколько шаблонов в одном
регулярное выражение. Остерегайтесь ситуаций, требующих возврата
хотя.
my $regex = join '|', qw( foo bar baz );
LINE: while( <> ) {
print if /\b(?:$regex)\b/i;
}
Подробнее об эффективности регулярного выражения см. я Джеффри Фрейдл. Он объясняет, как
выражений двигателя и почему некоторые модели на удивление
неэффективен. Как только вы поймете, как perl применяет регулярные выражения,
вы можете настроить их для отдельных ситуаций.
Ответ 4
Я не совсем уверен, что вы ищете, но что-то в этом роде?
#!/usr/bin/perl
@regexes = ( qr/foo/ , qr/bar/ );
while ($line=<>){
chomp $line;
$match=0;
for $re (@regexes){
$match++ if ($line =~ $re);
}
print "$line matches $match regexes\n";
}
Вы также можете скомпилировать их все в один рег:
#!/usr/bin/perl
@regexes = ( qr/foo/ , qr/bar/ );
$allre= "(".join("|",@regexes).")";
$compiled=qr/$allre/;
while(<>){
chomp;
print "$_ matches ($1)\n" if /$compiled/;
}
Надеюсь, что это поможет.
Ответ 5
Если вы используете большое количество регулярных выражений, вас может заинтересовать Regexp:: Optimizer
См. в разделе синопсиса:
use Regexp::Optimizer;
my $o = Regexp::Optimizer->new;
my $re = $o->optimize(qr/foobar|fooxar|foozap/);
# $re is now qr/foo(?:[bx]ar|zap)/
Это может быть более эффективным, если вы хотите установить дополнительный модуль.