代码之家  ›  专栏  ›  技术社区  ›  StarGeek

Perl,将字符串拆分为键:值对,用于使用小写键(不带临时数组)的哈希

  •  2
  • StarGeek  · 技术社区  · 8 年前

    给定一个Key:Value对字符串,我想创建一个查找散列,但要使用小写键值。我可以用这个代码

    my $a="KEY1|Value1|kEy2|Value2|KeY3|Value3";
    my @a = split '\|', $a;
    my %b = map { $a[$_] = (  !($_ % 2) ? lc($a[$_]) : $a[$_])  } 0 .. $#a ;
    

    生成的散列将类似于以下转储程序输出:

    $VAR1 = {
              'key3' => 'Value3',
              'key2' => 'Value2',
              'key1' => 'Value1'
            };
    

    编辑: 我忘了说我不能用外部模块来做这个。它需要是基本的Perl。

    6 回复  |  直到 8 年前
        1
  •  5
  •   Grinnz    8 年前

    你可以用 pairmap 使用from List::Util执行此操作时,根本不需要中间数组。

    use strict;
    use warnings;
    use List::Util 1.29 'pairmap';
    my $str="KEY1|Value1|kEy2|Value2|KeY3|Value3";
    my %hash = pairmap { lc($a) => $b } split /\|/, $str;
    

    注意:不要使用 $a or $b 在sort(或List::Util pair function)块之外。它们是用于排序的特殊全局变量,只是声明 my $a 在一个作用域中,可以中断该作用域中的所有排序(以及List::Util pair函数)。一个简单的解决方法是立即用 $x 和 $y

        2
  •  2
  •   zdim    8 年前

    因为键值对必须在 | 你可以用正则表达式

    my $v = "KEY1|Value1|kEy2|Value2|KeY3|Value3";
    
    my %h = split /\|/, $v =~ s/([^|]+) \| ([^|]+)/lc($1).q(|).$2/xger;
    
        3
  •  1
  •   Matt Jacob    8 年前
    use strict;
    use warnings;
    
    use Data::Dumper;
    
    my $i;
    my %hash = map { $i++ % 2 ? $_ : lc } split(/\|/, 'KEY1|Value1|kEy2|Value2|KeY3|Value3');
    
    print Dumper(\%hash);
    

    输出:

    $VAR1 = {
              'key1' => 'Value1',
              'key2' => 'Value2',
              'key3' => 'Value3'
            };
    
        4
  •  1
  •   ikegami Gilles Quénot    8 年前

    为了好玩,这里有两个额外的方法。

    一个比原来便宜的(因为元素是别名而不是复制到 @_ ):

    my %hash = sub { map { $_ % 2 ? $_[$_] : lc($_[$_]) } 0..$#_ }->( ... );
    

    比原版更贵的:

    my %hash = ...;
    @hash{ map lc, keys(%hash) } = delete( @hash{ keys(%hash) } );
    
        5
  •  1
  •   Grinnz    8 年前

    更多可能的解决方案使用regex来完成所有的工作,但不是很漂亮,除非你真的喜欢regex:

    use strict;
    use warnings;
    my $str="KEY1|Value1|kEy2|Value2|KeY3|Value3";
    my %hash;
    my $copy = $str;
    $hash{lc $1} = $2 while $copy =~ s/^([^|]*)\|([^|]*)\|?//;
    
    use strict;
    use warnings;
    my $str="KEY1|Value1|kEy2|Value2|KeY3|Value3";
    my %hash;
    $hash{lc $1} = $2 while $str =~ m/\G([^|]*)\|([^|]*)\|?/g;
    
    use strict;
    use warnings;
    my $str="KEY1|Value1|kEy2|Value2|KeY3|Value3";
    my %hash = map { my ($k, $v) = split /\|/, $_, 2; (lc($k) => $v) }
      $str =~ m/([^|]*\|[^|]*)\|?/g;
    
        6
  •  0
  •   Greg Nisbet    8 年前

    这里的解决方案改变了 split 在匹配语句上循环。

    #! /usr/bin/env perl
    
    use strict;
    use warnings;
    use Data::Dumper;
    
    my $a="KEY1|Value1|kEy2|Value2|KeY3|Value3";
    
    sub normalize_alist_opt {
      my ($input) = @_;
    
      my %c;
      my $last_key;
      while ($input =~ m/([^|]*(\||\z)?)/g) {
        my $s = $1;
        next unless $s ne '';
        $s =~ s/\|\z//g;
        if (defined $last_key) {
          $c{ lc($last_key) } = $s;
          $last_key = undef;
        } else {
          $last_key = $s;
        }
      }
    
      return \%c;
    }
    
    print Dumper(normalize_alist_opt($a));
    

    分裂 可以 识别并优化特例。尽管基于讨论 here 和 here

    sub normalize_alist {
      my ($input) = @_;
    
      my %c;
      my $last_key;
      foreach my $s (split /\|/, $input) {
        if (defined $last_key) {
          $c{ lc($last_key) } = $s;
          $last_key = undef;
        } else {
          $last_key = $s;
        }
      }
    
      return \%c;
    }