如何更改哈希键的大小写?

9

我正在编写一份脚本,用户有可能会对其进行修改。目前,我将配置设置存储在该脚本内部,以哈希表的形式存在于其中。

我想防止人们在哈希键中意外使用小写字母,因为那样会破坏我的脚本。

检查哈希键并仅对任何具有小写字符的键发出警告是很简单的,但我更愿意自动修复大小写问题。

换言之,我想将顶层哈希表中的所有哈希键转换为大写字母。

4个回答

17

安迪的回答是不错的,除了他会对每个键使用 uc 函数,而且如果不匹配还会再次使用 uc 函数。

这样只需使用一次 uc 函数:

%hash = map { uc $_ => $hash{$_} } keys %hash;

但是,既然你提到了用户存储密钥,那么使用tie(领带)是一种更加稳妥的方式,尽管速度较慢。

package UCaseHash;
require Tie::Hash;

our @ISA = qw<Tie::StdHash>;

sub FETCH { 
    my ( $self, $key ) = @_;
    return $self->{ uc $key };
}

sub STORE { 
    my ( $self, $key, $value ) = @_;
    $self->{ uc $key } = $value;
}

1;

接下来在主函数中:

tie my %hash, 'UCaseHash'; 

那是一个展示。使用 tie “魔法” 封装它,这样用户就不能不知情地搞乱它。

当然,只要您使用了“class”,就可以传入配置文件名称并从那里进行初始化:

package UCaseHash;
use Tie::Hash;
use Carp qw<croak>;

...

sub TIEHASH { 
    my ( $class_name, $config_file_path ) = @_;
    my $self = $class_name->SUPER::TIEHASH;
    open my $fh, '<', $config_file_path 
        or croak "Could not open config file $config_file_path!"
        ;
    my %phash = _process_config_lines( <$fh> );
    close $fh;
    $self->STORE( $_, $phash{$_} ) foreach keys %phash;
    return $self;
}

您需要这样调用它:
tie my %hash, 'UCaseHash', CONFIG_FILE_PATH;

假设一些常量为 CONFIG_FILE_PATH


1
你知道吗,CPAN上有一个模块可以做到这一点。不需要自己编写代码:Hash::Case,请参见http://search.cpan.org/dist/Hash-Case/。 - bart
你的方法将覆盖整个哈希表,而安迪的方法只会覆盖小写的键。除非你期望哈希表包含大量小写键(在这种情况下不太可能),否则它不会更快。 - Leon Timmermans
1
谢谢提醒,巴特。我忘了 Perl 俱乐部的第一条规则:在检查 CPAN 之前不要发言。我的帖子最初只是一个关于 tied 类的简单示例,然后我变得过于花哨了。唉! - Axeman
1
感谢你的观点,Leon。但我不喜欢丢弃已经计算过的数据,这并不一定是关于速度的问题。在我看来,我的表达方式更加功能化。 - Axeman

12

遍历散列表,并将任何小写键替换为它们的大写等效项,并删除旧键。 大致实现如下:

for my $key ( grep { uc($_) ne $_ } keys %hash ) {
    my $newkey = uc $key;
    $hash{$newkey} = delete $hash{$key};
}

0

这将把多级哈希转换为小写

my $lowercaseghash = convertmaptolowercase(\%hash);

sub convertmaptolowercase(){
    my $output=$_[0];
    while(my($key,$value) = each(%$output)){
        my $ref;
        if(ref($value) eq "HASH"){
            $ref=convertmaptolowercase($value);
        } else {
           $ref=$value;
        }
        delete $output->{$key}; #Removing the existing key
        $key = lc $key;
        $output->{$key}=$ref; #Adding new key
    }
    return $output;
}

-1

我来这里寻找答案,想和大家分享我的学习心得。为确保 GET/POST 参数、模板和存储过程的兼容性,我希望通过 $cgi->Vars 获取的所有键都是大写的,并且没有剩余的小写“重复”键。以下是基本脚本...

use CGI;
use Data::Dumper;

my $cgi = CGI->new;

print "Content-Type: text/html\n\n";

$params = $cgi->Vars();

print "<p>Before - ", Dumper($params);

map { 
    if ( $_ =~ qr/[a-z]+/mp ){ 
        $params->{uc $_} = $params->{$_}; 
        delete($params->{$_}); 
    }  
} keys %{$params};

print "<p>After - ", Dumper($params);

exit;

输出看起来像这样...

Before - $VAR1 = { 'table' => 'orders', 'SALESMAN_ID' => '2', 'customer_id' => '49' };

After - $VAR1 = { 'SALESMAN_ID' => '2', 'TABLE' => 'orders', 'CUSTOMER_ID' => '49' };

这段代码中有一些奇怪的事情。你基本上在做Axeman所做的事情,但是使用了一些不太好的实践和一些额外的步骤。 - brian d foy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接