我有一个字符串数组,我想提取数组的元素 在包含关键字'start'的字符串之间,直到包含字符';'的字符串发生。 这些关键字之间的元素应该由一个空格拆分并写入散列。
示例:对于数组(" kk", "aa1", " 1 asa ", " start", "a 1", "b 2", "c 3", ";", "aaa")
,我想提取键/值对a 1
,b 2
,c 3
并将它们写入散列。
我的实现给出了正确的结果,但相当幼稚,涉及循环和嵌套的if语句:
my @lines = ( "z 10", " start", "a 1", "b 2", "c 3", ";", "aaa" );
my %map;
my $start;
foreach my $line (@lines) {
chomp $line;
if ( $line =~ m/start/ ) {
$start = 1;
}
else {
if ($start) {
if ( $line =~ m/;/ ) {
last;
}
my @arr = split " ", $line;
$map{ $arr[0] } = $arr[1];
}
}
}
foreach my $k ( keys %map ) {
my $val = $map{$k};
print "Key : $k val : $val \n";
}
有更优雅的方法吗?
答案 0 :(得分:2)
使用单个map
调用可以做到最完整:
my @subset = grep { /start/../;/ } @lines;
my %map = map split, @subset[1 .. $#subset-1];
for my $k (keys %map) {
my $val = $map{$k};
print "Key : $k val : $val \n";
}
<强>输出强>
Key : a val : 1
Key : c val : 3
Key : b val : 2
答案 1 :(得分:1)
这个问题是触发器操作员的理想选择......
use strict;
use warnings;
use Data::Dumper;
my @lines = (" kk", "aa1", " 1 asa ", " start", "a 1", "b 2", "c 3", ";", "aaa");
my @sub;
foreach (@lines) {
push(@sub, split) if (/ start/ .. /\;/); # flip flop
}
shift @sub; # Remove the start flag.
pop @sub; # Remove the end flag.
my %hash = @sub; # Convert to hash.
print Dumper(\%hash);
输出:
$VAR1 = {
'c' => '3',
'a' => '1',
'b' => '2'
};
触发器是/ start / .. / end / part。
正如评论中所指出的,这可以进一步重构为:
my @sub = map +split, grep { / start/ .. /;/ } @lines;
shift @sub;
pop @sub;
my %hash = @sub;
或者:
my @sub = map { / start/ .. /;/ ? split : () } @lines;
shift @sub;
pop @sub;
my %hash = @sub;
这些实现了相同的结果,但我已经离开了我的第一个解决方案,因为我认为这有助于说明触发器操作员正在做什么。
答案 2 :(得分:1)
考虑到它的可读性,我实际上最喜欢Borodin的解决方案。
但是,您可以对范围返回值进行测试以限制结果:
use strict;
use warnings;
my @lines = ( "z 10", " start", "a 1", "b 2", "c 3", ";", "aaa" );
my %hash = map {split} grep {
my $r = /start/ .. /;/;
$r && $r !~ /^1$|E/
} @lines;
use Data::Dump;
dd \%hash;
输出:
{ a => 1, b => 2, c => 3 }