【问题标题】:Case insensitive hash keys perl不区分大小写的哈希键 perl
【发布时间】:2016-11-29 11:07:55
【问题描述】:

问题

我有一个散列/数组结构,但有些散列键的情况不同。

我想知道是否有一种方法可以在不手动检查每个哈希的键的情况下处理这种情况。

在下面的示例中,我希望打印所有 ID/iD/id/Id 字段。


示例代码

use warnings;
use strict;


my $Hash = {
   Server  =>   [
                        {
                                Id=>123
                        },
                        {
                                iD=>456
                        },
                        {
                                ID=>789
                        }
                ]

};

for (@{$Hash->{Server}}){
        print "$_->{ID}\n"
        #This is the problematic part
}

其他

perl 版本:v5.10.0

这些数据是从其他地方收到的,并且必须保持相同的大小写,上面的示例是最小的,我不能简单地将它们全部更改为相同的大小写。

如果需要更多信息,请告诉我。

【问题讨论】:

  • 你在解析什么来得到这个数据结构?
  • @Sobrique 我喜欢在研究资料时识别出答案的名称。 :)
  • @Sobrique XML。我无法更改收到的 xml。
  • 不,但您可能可以使用更好的解析器。因为这看起来你已经使用了XML::Simple,而这只是一条通往痛苦的道路。如果您发布一些示例 XML 我可能会给您一个更好的解决方案。
  • XML::Twiglc_attnames 可能完全符合您的要求。

标签: linux perl


【解决方案1】:

嗯,这在一定程度上取决于您的信息来源。这看起来像你已经解析了一些东西,所以可能有更好的解决方案。

但是,根据我们这里的情况,我会这样做:

for my $entry (@{$Hash->{Server}}){
   #grep, find first match. Dupes discarded. 
   my ( $key ) = grep { /^id$/i } keys %$entry; 
   print "$key => ",$entry -> {$key},"\n";
}

这可以通过在keys 上使用grepi 正则表达式来实现不区分大小写,并抓住最先出现的任何内容。因此,如果您对/id/i 有多个匹配项,那么您获得哪一个将是随机的。 (sort 可以帮助解决这个问题)

鉴于您正在使用 XML,我可能会回溯一下,扔掉 XML::Simple 并改为这样做:

#!/usr/bin/perl
use strict;
use warnings;

use XML::Twig;

my $twig = XML::Twig -> new ( twig_handlers => { '_all_' => sub { $_ -> lc_attnames }} );
   $twig -> parse ( \*DATA );

print "XML looks like:\n";
$twig -> set_pretty_print ( 'indented_a'); 
$twig -> print;

print "Output:\n";

foreach my $server ( $twig -> get_xpath('//Server') ) { 
    print $server -> att('id'),"\n";
}

__DATA__
<XML>
   <Server ID="123" />
   <Server Id="456" />
   <Server id="789" />
</XML>

或者你可以:

foreach my $server ( $twig -> get_xpath('//Server') ) {
    $server -> lc_attnames;
    print $server -> att('id'),"\n";
}

代替在树枝处理程序中执行此操作。第一个答案会将您的所有 XML 都“修复”为具有小写属性,这可能不是您想要的。但是,它可能对其他场景有用,这就是我给出两个示例的原因。

【讨论】:

  • 我想知道哪种解决方案更便宜。您正在摸索所有键或我正在查看所有可能的键。
  • 真的很难说。我怀疑它首先取决于键的数量 - 只检查一个匹配是微不足道的,但如果有一堆冗余(非“id”),那么 grep 必须检查它们。
  • 就时间复杂度而言,我认为XML::Twig 解决方案更便宜,因为它不涉及任何嵌套循环。其他解决方案需要嵌套循环,这使得复杂性O(n*n)
  • 只是真正寻找答案的第一部分来处理哈希键,但 XML::Twig 示例是一个受欢迎的补充 :)
  • 老实说 - 如果您在实施道路上还没有走得太远,从长远来看,从 XML::Simple 切换会极大地帮助您。如果您真的需要,XML::Twig 甚至可以使用 simplify 方法进行替换。
【解决方案2】:

没有内置的方法可以做到这一点。您可以做的是使用List::Util's first 至少获得更少的检查,然后仍然尝试直到每个键都适合。

use strict;
use warnings;
use feature 'say';
use List::Util 'first';

my $Hash = {
    Server => [
        {
            Id => 123
        },
        {
            iD => 456
        },
        {
            ID => 789
        }
    ]
};

foreach my $thing ( @{ $Hash->{Server} } ) {

    #                     this returns the first match in the list, like grep   
    #   so we need to use it here to return the actual value
    say $thing->{ first { $thing->{$_} } qw/id ID iD Id/ };
}

如果数据结构中有很多其他键,这比查看所有键便宜,因为您最多查找所有可能的 id 键加一个,最多两个.

如果您希望自动生成可能的键列表并且可以任意混合大小写字母,请查看this answer

【讨论】:

    【解决方案3】:

    我建议您使用正则表达式来忽略使用 i 标志的键的大小写。

    for my $item ( @ { $Hash->{Server} }) {
        for(keys %{$item}) {
            print $item -> {$_},"\n" if /^ID$/i;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2016-09-04
      • 1970-01-01
      • 2010-09-23
      • 1970-01-01
      • 1970-01-01
      • 2012-05-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多