我使用DBI连接到Sybase来获取hash_ref元素中的记录。Sybase驱动程序有一个讨厌的习惯,就是返回带有尾随字符的记录,特别是在我的例子中是\x00。我正在尝试编写一个函数来清理hashref中的所有元素,下面的代码可以做到这一点,但我找不到一种方法来使它更精简,我知道有一种方法可以做得更好:
#!/usr/bin/perl
my $dbh = DBI->connect('dbi:Sybase:...');
my $sql = qq {SELECT * FROM table WHERE age > 18;};
my $qry = $dbh->selectall_hashref($sql, 'Name');
foreach my $val(values %$qry) {
$qry->{$val} =~ s/\x00//g;
}
foreach my $key(keys %$qry) {
$qry->{$key} =~ s/\x00//g;
foreach my $val1(keys %{$qry->{$key}}) {
$qry->{$key}->{$val1} =~ s/\x00//g;
}
foreach my $key1(keys %{$qry->{$key}}) {
$qry->{$key}->{$key1} =~ s/\x00//g;
}发布于 2012-01-25 09:44:59
虽然我认为正则表达式替换并不是一个理想的解决方案(似乎应该正确地解决它),但这里有一个使用chomp解决它的便捷方法。
use Data::Dumper;
my %a = (
foo => {
a => "foo\x00",
b => "foo\x00"
},
bar => {
c => "foo\x00",
d => "foo\x00"
},
baz => {
a => "foo\x00",
a => "foo\x00"
}
);
$Data::Dumper::Useqq=1;
print Dumper \%a;
{
local $/ = "\x00";
chomp %$_ for values %a;
}
print Dumper \%a;无论输入记录分隔符$/设置为什么值,chomp都会删除一个拖尾值。当在散列上使用时,它将吞噬这些值。
正如您将注意到的,我们不需要直接使用这些值,因为它们有别名。还要注意在local $/语句周围使用块来限制其作用域。
要获得更易于管理的解决方案,最好是创建一个递归调用的子例程。我在这里再次使用了chomp,但是您可以很容易地跳过这一步,直接使用s/\x00//g。或者tr/\x00//d,它基本上做同样的事情。与s/\x00$//一样,chomp只删除字符串末尾的字符,因此更安全。
strip_null(\%a);
print Dumper \%a;
sub strip_null {
local $/ = "\x00";
my $ref = shift;
for (values %$ref) {
if (ref eq 'HASH') {
strip_null($_); # recursive strip
} else {
chomp;
}
}
}发布于 2012-01-25 09:09:35
首先是你的代码:
foreach my $val(values %$qry) {
$qry->{$val} =~ s/\x00//g;
# here you are using a value as if it was a key
}
foreach my $key(keys %$qry) {
$qry->{$key} =~ s/\x00//g;
foreach my $val1(keys %{$qry->{$key}}) {
$qry->{$key}->{$val1} =~ s/\x00//g;
}
foreach my $key1(keys %{$qry->{$key}}) {
$qry->{$key}->{$key1} =~ s/\x00//g;
}
# and this does the same thing twice...你应该做的是:
foreach my $x (values %$qry) {
foreach my $y (ref $x eq 'HASH' ? values %$x : $x) {
$y =~ s/(?:\x00)+$//
}
}这将仅清理散列的两个级别的值中的结尾空值。
循环的主体也可以写成:
if (ref $x eq 'HASH') {
foreach my $y (values %$x) {
$y =~ s/(?:\x00)+$//
}
}
else {
$x =~ s/(?:\x00)+$//
}但这会迫使您编写两次替换,并且您不应该重复自己。
或者,如果您真的想减少代码,使用隐式$_变量效果很好:
for (values %$qry) {
s/(?:\x00)+$// for ref eq 'HASH' ? values %$_ : $_
}https://stackoverflow.com/questions/8996536
复制相似问题