Как проверить, есть ли в скаляре скомпилированное регулярное выражение с Perl? - PullRequest
4 голосов
/ 02 апреля 2010

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

sub test_output {
    my ($self, $test) = @_;
    my $output = $self->long_process_to_get_data();
    if ($output =~ /\Q$test/) {
        $self->assert_something();
    }
    else {
        $self->do_something_else();
    }
}

Обычно $test - это строка, которую мы ищем в любом месте вывода. Это был интерфейс, созданный для упрощения вызова. Однако мы обнаружили, что иногда прямая строка проблематична - например, большое, возможно, различное количество пробелов ... шаблон, если хотите. Таким образом, я хотел бы позволить им передать регулярное выражение в качестве опции. Я мог бы просто сделать:

$output =~ $test

если бы я мог предположить, что это всегда регулярное выражение, но ах, но обратная совместимость! Если они передают строку, ей все равно нужно проверить ее как необработанную строку.

Так что в этом случае мне нужно проверить, является ли $test регулярным выражением. Есть ли какая-нибудь хорошая возможность определить, есть ли в скаляре скомпилированное регулярное выражение?

Ответы [ 3 ]

18 голосов
/ 02 апреля 2010

Поскольку hobbs указывает на , если вы уверены, что будете на 5.10 или более поздней версии, вы можете использовать встроенную проверку:

 use 5.010;
 use re qw(is_regexp);
 if (is_regexp($pattern)) {
     say "It's a regex";
 } else {
     say "Not a regex";
 }

Однако у меня не всегда есть такая опция. В общем, я делаю это путем проверки значения прототипа с помощью ref :

 if( ref $scalar eq ref qr// ) { ... }

Одна из причин, по которой я начал это делать, заключалась в том, что я никогда не мог вспомнить имя типа для ссылки на регулярное выражение. Я даже не могу вспомнить это сейчас. Он также не в верхнем регистре, как остальные, потому что на самом деле это один из пакетов, реализованных в исходном коде perl (в regcomp.c , если вы хотите его увидеть).

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

 use constant REGEX_TYPE => ref qr//;

Я подробно об этом говорю в Эффективное программирование на Perl как «Элемент 59: Сравните значения с прототипами».

Если вы хотите попробовать это обоими способами, вы можете использовать проверку версии на Perl:

 if( $] < 5.010 ) { warn "upgrade now!\n"; ... do it my way ... }
 else             { ... use is_regex ... }
10 голосов
/ 02 апреля 2010

Начиная с perl 5.10.0, есть прямой, не хитрый способ сделать это:

use 5.010;
use re qw(is_regexp);
if (is_regexp($pattern)) {
    say "It's a regex";
} else {
    say "Not a regex";
}

is_regexp использует тот же внутренний тест, который использует perl, что означает, что в отличие от ref, он не будет обманут, если по какой-то странной причине вы решите благословить объект регулярного выражения в классе, отличном от Regexp (да, это возможно).

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

3 голосов
/ 02 апреля 2010

См. ref встроенный.

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