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

Perl,将字符串拆分为键:值对,用于使用小写键(不带临时数组)进行哈希,perl,hash,Perl,Hash,给定一个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'

给定一个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'
        };
是否可以直接创建哈希%b而不使用临时数组@a,或者是否有更有效的方法来实现相同的结果


编辑:我忘了提到我不能使用外部模块。它需要是基本的Perl。

因为键值对必须在
附近,所以可以使用正则表达式

my $v = "KEY1|Value1|kEy2|Value2|KeY3|Value3";

my %h = split /\|/, $v =~ s/([^|]+) \| ([^|]+)/lc($1).q(|).$2/xger;
您可以使用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;
注意:永远不要使用排序(或List::Util pair函数)块之外的块。它们是用于排序的特殊全局变量,只需在一个作用域中声明
my$a
,就可以中断该作用域中的所有排序(以及List::Util pair函数)。一个简单的解决方案是,当您发现自己开始使用它们作为示例变量时,立即将它们替换为
$x
$y

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'
        };

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

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

比原版更贵的:

my %hash = ...;
@hash{ map lc, keys(%hash) } = delete( @hash{ keys(%hash) } );

这里有一个解决方案,可以避免对输入字符串进行变异、构造与输入字符串长度相同的新字符串或在内存中创建中间数组

这里的解决方案将
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));
直接通过
拆分操作的潜在解决方案。Perl可能会识别并优化这种特殊情况。尽管基于讨论和讨论,我不确定

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;
}

更多可能的解决方案使用正则表达式来完成所有工作,但除非您真的喜欢正则表达式,否则不是很漂亮:

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;

很抱歉,我忘了提到我不能使用外部模块来实现这一点。编辑问题以反映这一点。谢谢你关于a美元和b美元的便条。虽然我只是在本例中使用它们作为示例,但我要记住这一点。@StarGeek List::Util不是一个外部模块,它是核心。@StarGeek如果您的List::Util对于pairmap来说太旧了(5.20之前的Perl,您无法升级模块),那么您将非常需要一个丑陋的单行程序或两行程序,正如其他答案所述。这个解决方案不是最有效的,但它肯定是最清晰的。不管OP怎么想,这里效率不是关键。@StarGeek我把问题倒过来,更新了(并修复了一个错误)
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;