Нечувствительные к регистру хэш-ключи в Regexp::Grammars
В модуле Perl Regexp::Grammars рассмотрите следующий токен:
<token: command> <%commands>
Этот токен является частью сложной грамматики, разбирающей множество различных предложений.
Этот токен соответствует любому слову в командах hash %, которые я определил следующим образом (конечно, вне любой функции):
our %commands = (
'Basic_import' => 1,
'Wait' => 1,
'Reload' => 1,
'Log' => 1,
);
Это работает для сопоставления ключевых слов, таких как "Basic_import", "Wait" и т. Д. Однако я также хочу, чтобы оно совпадало с такими словами, как "basic_import", "wait" и т. Д.
Как сделать этот регистр нечувствительным к регистру без необходимости копировать и вставлять каждое ключевое слово несколько раз? Поскольку это часть сложной грамматики, я хочу использовать Regexp::Grammars, и я бы предпочел не возвращаться к grep для этого конкретного исключения.
2 ответа
Вы можете использовать https://metacpan.org/pod/Hash::Case::Preserve, чтобы сделать поиск по хешу нечувствительным к регистру:
use strict;
use warnings 'all';
use Data::Dump;
use Hash::Case::Preserve;
use Regexp::Grammars;
tie my %commands, 'Hash::Case::Preserve';
%commands = (
'Basic_import' => 1,
'Wait' => 1,
'Reload' => 1,
'Log' => 1,
);
my $grammar = qr{
<command>
<token: command> <%commands>
};
dd \%/ if 'basic_import' =~ $grammar;
Выход:
{ "" => "basic_import", "command" => "basic_import" }
Обратите внимание, что вы должны tie
хэш перед вставкой в него любых значений.
Из документации это звучит как <%commands>
будет соответствовать Wait
из Waiting
так что даже без учета регистра версия <%commands>
будет меньше, чем идеал.
Обычно вы хотите сопоставить общий идентификатор и независимо проверить, является ли этот идентификатор допустимой командой. Это то, что мешает printfoo();
быть эквивалентным print foo();
в перл.
Могу ли я предложить следующее:
use feature qw( fc );
our %commands = map { fc($_) => 1 } qw(
Basic_import
Wait
Reload
Log
);
<rule: command> (<ident>) <require: (?{ $commands{fc($CAPTURE)} })>
<token: ident> \w+
Вы, вероятно, можете сойти с рук с помощью lc
вместо fc
если вам нужна обратная совместимость с версией Perl старше 5.16.
%commands = map { lc($_) => 1, $_ => 1 } qw(
Basic_import
Wait
Reload
Log
);