Как сопоставить два значения независимо от их соответствующих позиций в строке - PullRequest
3 голосов
/ 14 декабря 2010

Я ищу лучший способ сопоставить два значения одновременно.

Я хотел бы получить истинное значение, если оба значения находятся в строке, но я не знаю, в каком порядке они отображаютсяв строке (например, abcdef или bedfa в случае, если я хочу сопоставить a и b)

Есть ли лучшее решение (особенно если позже мне понадобятся более сложные значения для сопоставления)чем:

$string =~ m/(a.*b)|(b.*a)/i

Ответы [ 4 ]

11 голосов
/ 14 декабря 2010
$string =~ /a/i && $string =~ /b/i;
5 голосов
/ 14 декабря 2010

Вы можете использовать положительный прогноз как:

$string =~ /^(?=.*a)(?=.*b).*$/i

В общем, если вы хотите проверить наличие foo и bar в любом месте строки, вы можете сделать:

$string =~ /^(?=.*foo)(?=.*bar).*$/i

И если вы хотите, чтобы foo и bar были отдельными словами, а не подстрокой любого другого слова, вы можете добавить границу слова как:

$string =~ /^(?=.*\bfoo\b)(?=.*\bbar\b).*$/i

Позже, если вы хотите добавить проверку на существование baz, вы можете просто сделать:

$string =~ /^(?=.*\bfoo\b)(?=.*\bbar\b)(?=.*\bbaz\b).*$/i
3 голосов
/ 15 декабря 2010

Чтобы расширить мои комментарии, приведу сравнение нескольких представленных решений.

#!/usr/bin/perl

use strict;
use warnings;
use Benchmark qw(cmpthese);

my $two_regexp = q{
    for my $string ('This and that', 'Not that, this!', 'do not match this') {
        if ($string =~ /this/i && $string =~ /that/i) {
            1;
        }
    }
};

my $alternation = q{
    for my $string ('This and that', 'Not that, this!', 'do not match this') {
        if ($string =~ m/(this.*that)|(that.*this)/i) {
            1;
        }
    }
};

my $alternation_no_capture = q{
    for my $string ('This and that', 'Not that, this!', 'do not match this') {
        if ($string =~ m/(?:this.*that)|(?:that.*this)/i) {
            1;
        }
    }
};

my $anchored_lookahead = q{
    for my $string ('This and that', 'Not that, this!', 'do not match this') {
        if ($string =~ /^(?=.*this)(?=.*that).*$/i) {
            1;
        }
    }
};

my $start_anchored_lookahead = q{
    for my $string ('This and that', 'Not that, this!', 'do not match this') {
        if ($string =~ /^(?=.*this)(?=.*that)/i) {
            1;
        }
    }
};

my $free_lookahead = q{
    for my $string ('This and that', 'Not that, this!', 'do not match this') {
        if ($string =~ /(?=.*this)(?=.*that)/i) {
            1;
        }
    }
};

cmpthese(-1, {
    two_regexp               => $two_regexp,
    alternation              => $alternation,
    alternation_no_capture   => $alternation_no_capture,
    anchored_lookahead       => $anchored_lookahead,
    start_anchored_lookahead => $start_anchored_lookahead,
    free_lookahead           => $free_lookahead,
});

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

                             Rate free_lookahead alternation alternation_no_capture anchored_lookahead start_anchored_lookahead two_regexp
free_lookahead           170836/s             --        -55%                   -61%               -61%                     -67%       -73%
alternation              378300/s           121%          --                   -13%               -13%                     -27%       -40%
alternation_no_capture   432784/s           153%         14%                     --                -1%                     -17%       -31%
anchored_lookahead       436906/s           156%         15%                     1%                 --                     -16%       -30%
start_anchored_lookahead 518950/s           204%         37%                    20%                19%                       --       -17%
two_regexp               628278/s           268%         66%                    45%                44%                      21%         --

Так что, по крайней мере, для моего эстетического чувства и версии Perl использование двух совпадений выигрывает в обоих направлениях.

1 голос
/ 14 декабря 2010

Почему бы не это?

$string =~ /a/i && $string =~ /b/i

Это более разборчиво.

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