Есть ли способ скомпилировать возвращаемое значение некоторой функции в регулярное выражение в одном выражении? - PullRequest
3 голосов
/ 24 апреля 2020

Мне нужно построить регулярное выражение, которое соответствует любому ключу в данном га sh. Этого легко достичь с помощью

my $string = join('|', keys %hash);
my $regex = qr/$string/;

, где %hash - га sh, о которой идет речь. Из любопытства: есть ли способ обойти введение фиктивной переменной $string и напрямую скомпилировать возвращаемое значение произвольной функции в регулярное выражение (кроме определения собственного подпрограммы или прототипа)? Сформулированы по-разному: qr также имеет функциональную форму (например, readpipe для qx)?

Заранее спасибо!

Ответы [ 4 ]

5 голосов
/ 24 апреля 2020

Вы можете интерполировать произвольный код в любую двойную sh конструкцию (qq, qr, qx). $foo интерполирует скалярную переменную. ${ code-returing-a-scalar-reference } интерполирует произвольный код. Поэтому, чтобы избежать фиктивной переменной, вы делаете:

my $regex = qr/${ \join('|', keys %hash) }/;

Но, как уже упоминалось в комментарии, если вы хотите сопоставить только строку, равную одному из ключей, вы хотите добавить \A (или ^) и \z якоря. В противном случае вы сопоставите любую строку, содержащую один из ключей.

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

my $regex = qr/\A(?:${ \join('|', map quotemeta, sort keys %hash) })\z/;
3 голосов
/ 24 апреля 2020

С некоторыми предупреждениями один может сделать это, используя расширенный шаблон (??{ code })

use warnings;
use strict;
use feature 'say';

sub form_patt { return '[0-9]+' }

my $re = qr/ [a-z] (??{ form_patt() }) /x; 
#say $re;

my $v = q(z23 b71);
my @m = $v =~ /($re)/g; 
say "@m";

Конструкция позволяет любому коду Perl выполняться внутри шаблон, и возвращаемое значение этого кода

обрабатывается как шаблон, компилируется, если это строка (или используется как есть, если это qr// объект), а затем сопоставляется, как если бы он были вставлены вместо этой конструкции.

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

Недостатком является то, что его вполне можно оценивать каждый раз, когда его используют (даже если в переменной с qr объектом). Кроме того, это сложная особенность; пожалуйста, смотрите документацию.


Это регулярное выражение нуждается в корректировках, как обсуждалось; по крайней мере, чтобы экранировать ASCII не-словесных символов с quotemeta . Скорее всего, шаблоны также должны быть привязаны (привязаны).

Если ключи входят в более длинную строку (более широкое требование, чем в ответе на ysth), то привязайте шаблон к границе слова \b, чтобы искать key не соответствует keys

'\b(?:' . join('|', map { quotemeta } keys %hash) . ')\b'

Это одна возможность, в зависимости от точных требований, которые не были даны.

2 голосов
/ 25 апреля 2020

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

join '|', map quotemeta, keys %hash

В ответ на свой вопрос вы можете использовать любой из следующих :

my ($re) = map qr/$_/, EXPR;

my $re = ( map qr/$_/, EXPR )[0];

Итак, вы бы использовали

my ($re) = map qr/$_/, join '|', map quotemeta, keys %hash;

my $re = ( map qr/$_/, join '|', map quotemeta, keys %hash )[0];
1 голос
/ 25 апреля 2020

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

Regex :: Assemble может взять список шаблонов и сделать эффективное чередование.

используйте Regexp :: Assemble;

use Regexp::Assemble;

my %hash = map { $_, 1 } qw(cat concat bird dog doge . [ | );

my $ra = Regexp::Assemble->new;
$ra->add( map { quotemeta } keys %hash );

print $ra;

И вот его регулярное выражение:

(?^:(?:[.[]|(?:con)?cat|doge?|bird|\|))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...