优雅地解析Perl中的刚性数据

时间:2010-12-11 05:30:27

标签: perl parsing coding-style

我正在使用一个大型数据集,基本上归结为这样的东西:

my $input = q(
<foo>111</foo>
<foo>222</foo>
<foo>333</foo>
<foo></foo>
<foo>555</foo>
); # new-lines are either CR+LF, LF, or CR

基于上面的例子,我们假设以下约束有效:

  • 总会有5行数据。
  • 每行中的数据都包含在一个标记中,例如<foo>...</foo>
  • 数据不包含嵌套标签。
  • 所有行都使用相同的标记(例如foo)来包含其数据。

最终,以上面的数据来源为例,我想最终得到类似的东西:

my %values = (
  one   => '111',
  two   => '222',
  three => '333',
  four  => '',
  five  => '555'
);

这是我的尝试:

my @vals = $input =~ m!<foo>(.*?)</foo>!ig;

if (scalar @vals != 5) {
  # panic
}

my %values = (
  one   => shift @vals,
  two   => shift @vals,
  three => shift @vals,
  four  => shift @vals,
  five  => shift @vals
);

这是我想要的,但它看起来很丑,并不是很灵活。不幸的是,这是我现在能做的最好的事情,因为我是Perl的新手。

所以,鉴于上述限制,有什么更优雅的方法呢?

3 个答案:

答案 0 :(得分:4)

将两个数组合并为一个哈希:

my @keys = qw/one two three/;
my @values = qw/alpha beta gamma/;

my %hash; 
@hash{@keys} = @values;

答案 1 :(得分:3)

首先,再看看:

my %values = (
  one   => '111',
  two   => '222',
  three => '333',
  four  => '',
  five  => '555'
);

此数据结构将整数与一段数据相关联。但是已经存在一个内置数据结构,它具有相同的用途:Arrays。

所以,使用数组。您可以编写$values{ one }而不是编写$values[ 0 ],而整数和数据值之间的映射将是透明的。

如果键不是整数,则可以执行以下操作:

use strict; use warnings;

my @keys = qw(a b c d e);

my $input = q(
<foo>111</foo>
<foo>222</foo>
<foo>333</foo>
<foo></foo>
<foo>555</foo>
); # new-lines are either CR+LF, LF, or CR

my %values;

# hash slice
@values{ @keys } = $input =~ m{ <foo> (.*?) </foo>}gix;

use YAML;
print Dump \%values;

输出:

---
a: 111
b: 222
c: 333
d: ''
e: 555

答案 2 :(得分:2)

哦,这样的东西可以给予还是带走?

use Number::Spell;
$input =~ s|<(?:/)?foo>||g;
my @lines = grep { $_ } split "\n", $input; # grep for blank lines
my $i = 0;
my %hash = map { spell_number($i++) => $_ } @lines;
嗯,我可以做得更好。

use Number::Spell;
my $i = 0;
my %hash = map { s|<(?:/)?foo>||g; $_ ? spell_number($i++) => $_ : () } 
           split "\n", $input;

<强>编即可。哎呀,有一个@lines而不是$ input inna第二个片段。 谨慎使用;我只输入了这段代码;我还没有写过单元测试。