Perl Regex соответствуют строкам, которые содержат несколько слов - PullRequest
0 голосов
/ 21 января 2011

Я пытаюсь разработать довольно быстрый полнотекстовый поиск. Он прочитает индекс и в идеале должен выполнить сопоставление всего за одно регулярное выражение.

Поэтому мне нужно регулярное выражение, которое соответствует строкам, только если содержатся определенные слова.

например. для

my $txt="one two three four five\n".
        "two three four\n".
        "this is just a one two three test\n";

Должны совпадать только строки 1 и 3, поскольку строка 2 не содержит слова «один».

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

Пример отсюда: http://www.regular -expressions.info / completelines.html («Поиск строк, содержащих или не содержащих определенные слова»)

это то, что мне нужно. Однако я не могу заставить его работать в Perl. Я много пробовал, но ничего не получилось.

my $txt="one two three four five\ntwo three four\nthis is just a one two three test\n";
my @matches=($txt=~/^(?=.*?\bone\b)(?=.*?\btwo\b)(?=.*?\bthree\b).*$/gi);
print join("\n",@matches);

Не выводит.

В итоге: Мне нужно регулярное выражение для сопоставления строк, содержащих несколько слов, и возвращающих эти целые строки.

Заранее спасибо за помощь! Я так старался, но просто не заставлял его работать.

Ответы [ 2 ]

1 голос
/ 21 января 2011

Метасимволы ^ и $ по умолчанию соответствуют только началу и концу ввода.Чтобы они соответствовали началу и концу строк, включите флаг m (MULTI-LINE):

my $txt="one two three four five\ntwo three four\nthis is just a one two three test\n";
my @matches=($txt=~/^(?=.*?\bone\b)(?=.*?\btwo\b)(?=.*?\bthree\b).*$/gim);
print join("\n",@matches);

производит:

one two three four five
this is just a one two three test

Но, если вы действительно хотитебыстрый поиск, регулярные выражения (с большим количеством перспектив на будущее) - это не тот путь, если вы спросите меня.

0 голосов
/ 21 января 2011

Код:

use 5.012;
use Benchmark qw(cmpthese);
use Data::Dump;
use once;

our $str = <<STR;
one thing
another two
three to go
no war
alone in the dark
war never changes
STR

our @words = qw(one war two);

cmpthese(100000, {
    'regexp with o'             => sub {
        my @m;
        my $words = join '|', @words;
        @m = $str =~ /(?!.*?\b(?:$words)\b)^(.*)$/omg;
        ONCE { say 'regexp with o:'; dd @m }
    },
    'regexp'                    => sub {
        my @m;
        @m = $str =~ /(?!.*?\b(?:@{ [ join '|', @words ] })\b)^(.*)$/mg;
        ONCE { say 'regexp:'; dd @m }
    },
    'while'                     => sub {
        my @m;
        @m = grep $_ !~ /\b(?:@{ [ join '|',@words ] })\b/,(split /\n/,$str);
        ONCE { say 'while:'; dd @m }
    },
    'while with o'              => sub {
        my @m;
        my $words = join '|',@words;
        @m = grep $_ !~ /\b(?:$words)\b/o,(split /\n/,$str);
        ONCE { say 'while with o:'; dd @m }
    }
})

Результирующее:

regexp:
("three to go", "alone in the dark")
regexp with o:
("three to go", "alone in the dark")
while:
("three to go", "alone in the dark")
while with o:
("three to go", "alone in the dark")
                 Rate        regexp regexp with o         while  while with o
regexp        19736/s            --           -2%          -40%          -60%
regexp with o 20133/s            2%            --          -38%          -59%
while         32733/s           66%           63%            --          -33%
while with o  48948/s          148%          143%           50%            --

Сonclusion

Итак, вариант с while более быстрый, чем вариант с регулярным выражением`.

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