Regexp::Grammars 中不区分大小写的散列键

Case-insensitive hash-keys in Regexp::Grammars

在 perl 模块 Regexp::Grammars 中,考虑以下标记:

<token: command>       <%commands>

此标记是复杂语法的一部分,可解析各种不同的句子。

这个标记匹配散列 %commands 中的任何单词,我定义如下(当然,在任何函数之外):

our %commands = (
    'Basic_import'  => 1,
    'Wait'          => 1,
    'Reload'        => 1,
    'Log'           => 1,
); 

这适用于匹配 "Basic_import"、"Wait" 等关键字。但是,我还希望它匹配 "basic_import"、"wait" 等字词.

如何使这个散列不区分大小写,而不必多次复制和粘贴每个关键字?因为这是一个复杂语法的一部分,所以我想使用 Regexp::Grammars,并且我不想为了这个特定的异常而不得不恢复到 grep。

根据文档,听起来 <%commands> 会匹配 WaitingWait,因此即使 <%commands> 的不区分大小写的版本也不太理想。

您通常希望匹配通用标识符,并独立检查标识符是否为有效命令。这就是阻止 printfoo(); 等同于 Perl 中的 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+

如果你想向后兼容早于 5.16 的 Perl 版本,你可以使用 lc 而不是 fc

您可以使用 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 = map { lc($_) => 1, $_ => 1 } qw(
    Basic_import
    Wait
    Reload
    Log
);