Нечувствительные к регистру хэш-ключи в 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
);
Другие вопросы по тегам