你的Python的直接翻译是
my $re_is_comment_line = qr/^\s*#/;
my $re_key_values = qr/^\s*(\w+)\s*=\s*(.*)$/;
my $re_splitter = qr/\s*,\s*/;
my $is_interesting_line= sub {
my $_ = shift;
length($_) and not /$re_is_comment_line/ and /$re_key_values/;
};
sub parse {
my @lines = @_;
my @interesting_lines = grep $is_interesting_line->($_), @lines;
my @key_values = map [/$re_key_values/], @interesting_lines;
my %splitted_values = map { $_->[0], [split $re_splitter, $_->[1]] } @key_values;
return %splitted_values;
}
的差别:
ifilter
被称为grep
,并且可以代替块作为第一个参数的表达式。这些大致相当于一个拉姆达。当前项目在$_
变量中给出。这同样适用于map
。
- Perl并不强调懒惰,并且很少使用迭代器。有些情况下,这是必需的,但通常整个列表是一次评估。
在下面的例子,以下将被添加:
- 的正则表达式不必进行预编译,Perl是很好用正则表达式的优化。
- 我们使用
split
来代替用正则表达式提取关键字/值。它采用可选的第三个参数来限制结果片段的数量。
- 整个
map
/filter
东西可以写在一个表达式。这并没有提高效率,但强调了数据流。从底部向上读取map-map-grep(实际上从右到左,想想APL)。
。
sub parse {
my %splitted_values =
map { $_->[0], [split /\s*,\s*/, $_->[1]] }
map {[split /\s*=\s*/, $_, 2]}
grep{ length and !/^\s*#/ and /^\s*\w+\s*=\s*\S/ }
@_;
return \%splitted_values; # returning a reference improves efficiency
}
但是我觉得这里更优雅的解决方案是使用传统的循环:
sub parse {
my %splitted_values;
LINE: for (@_) {
next LINE if !length or /^\s*#/;
s/\A\s*|\s*\z//g; # Trimming the string—omitted in previous examples
my ($key, $vals) = split /\s*=\s*/, $_, 2;
defined $vals or next LINE; # check if $vals was assigned
@{ $splitted_values{$key} } = split /\s*,\s*/, $vals; # Automatically create array in $splitted_values{$key}
}
return \%splitted_values
}
如果我们决定通过文件句柄来代替,环路将与
my $fh = shift;
LOOP: while (<$fh>) {
chomp;
...;
}
取代
它将使用实际的迭代器。
您现在可以去添加功能参数,但是只有在您正在优化灵活性和没有其他任何其他。我已经在第一个例子中使用了一个代码引用。您可以使用$code->(@args)
语法来调用它们。
use Carp; # Error handling for writing APIs
sub parse {
my $args = shift;
my $interesting = $args->{interesting} or croak qq("interesting" callback required);
my $kv_splitter = $args->{kv_splitter} or croak qq("kv_splitter" callback required);
my $val_transform= $args->{val_transform} || sub { $_[0] }; # identity by default
my %splitted_values;
LINE: for (@_) {
next LINE unless $interesting->($_);
s/\A\s*|\s*\z//g;
my ($key, $vals) = $kv_splitter->($_);
defined $vals or next LINE;
$splitted_values{$key} = $val_transform->($vals);
}
return \%splitted_values;
}
此类型可称为像
my $data = parse {
interesting => sub { length($_[0]) and not $_[0] =~ /^\s*#/ },
kv_splitter => sub { split /\s*=\s*/, $_[0], 2 },
val_transform => sub { [ split /\s*,\s*/, $_[0] ] }, # returns anonymous arrayref
}, @lines;
这是具有挑战性的做用Perl真正的功能性编程。我会坚持一个更迭代的方法来读取文件。 – squiguy 2013-04-25 17:44:34