Как я могу сопоставить несколько регулярных выражений в Perl? - PullRequest
14 голосов
/ 12 сентября 2010

Я хотел бы проверить, соответствует ли какая-либо строка любому из заданного набора регулярных выражений.Как я могу это сделать?

Ответы [ 5 ]

20 голосов
/ 12 сентября 2010

Используйте интеллектуальное сопоставление, если у вас Perl версии 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's given / when делает это за кадром:

Большая часть власти исходит от неявного умного сопоставления, которое иногда может применяться.Большую часть времени when(EXPR) рассматривается как неявный смартматч $_, то есть $_ ~~ EXPR.(См. Оператор Smartmatch в perlop для получения дополнительной информации о smartmatching.)

«Оператор Smartmatch» в perlop дает таблицу многих комбинаций, которые вы можете использовать,и приведенный выше код соответствует случаю, когда $a равен Any , а $b равен Array , что примерно соответствует

grep $a ~~ $_, @$b

, за исключением короткого поиска-circuits, т.е. , быстро возвращает совпадение, а не обрабатывает все элементы.Тогда в неявном цикле мы умно сопоставляем Any с Regex , что составляет

$a =~ /$b/

Выход:

blurfl: miss.
bar: hit!
quux: miss.
foo: hit!
baz: hit!

Приложение

С тех пор, как этот ответ был изначально написан, дизайнеры Perl поняли, что в работе интеллектуального сопоставления были ошибки, и поэтому теперь считается экспериментальной функцией .Вышеупомянутый случай не является одним из спорных случаев, тем не менее вывод кода будет включать given is experimental и when is experimental, за исключением того, что я добавил no warnings 'experimental::smartmatch';.

Любое использование экспериментальных функций сопряжено с некоторым риском, но яоценил бы это как низкую вероятность для этого случая.При использовании кода, аналогичного описанному выше, и обновлении до более новой версии Perl, это потенциальная ошибка, о которой следует знать.

12 голосов
/ 12 сентября 2010

От ответа perlfaq6 на Как эффективно сопоставить много регулярных выражений одновременно? , в данном случае это последняя версия разработки, которую я только что обновил, с примером умного сопоставления.


Как эффективно сопоставить много регулярных выражений одновременно?

(предоставлено Брайаном Д Фой)

Если у вас есть 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, чтобы превратить каждый шаблон в его предварительно скомпилированную форму.Остальная часть сценария такая же, но быстрее:

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;
    }

Подробнее об эффективности регулярных выражений см. I by Jeffrey Freidl.Он объясняет, как работает механизм регулярных выражений и почему некоторые шаблоны удивительно неэффективны.Как только вы поймете, как Perl применяет регулярные выражения, вы можете настроить их для отдельных ситуаций.

10 голосов
/ 12 сентября 2010

Мой способ протестировать значение для нескольких регулярных выражений одновременно: Regexp :: Assemble , который "Собирает несколько регулярных выражений в один RE" способом, несколько более интеллектуальным и оптимизированным, чем простоделает join '|', @regexps.Вы также можете по умолчанию извлечь часть текста, которая соответствует, и, если вам нужно знать, какой шаблон соответствует, переключатель track предоставит эту информацию.Его производительность довольно хорошая - в одном приложении я использую его для одновременного тестирования 1700 шаблонов - и мне еще нужно что-то, чего он не делает.

3 голосов
/ 12 сентября 2010

Если вы используете большое количество регулярных выражений, вас может заинтересовать 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)/

Это может бытьболее эффективно, если вы хотите установить дополнительный модуль.

3 голосов
/ 12 сентября 2010

Я не совсем уверен, что вы ищете, но что-то в этом роде?

#!/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/;
}

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...