首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Perl Hashref替换

Perl Hashref替换
EN

Stack Overflow用户
提问于 2012-01-25 08:49:44
回答 2查看 289关注 0票数 0

我使用DBI连接到Sybase来获取hash_ref元素中的记录。Sybase驱动程序有一个讨厌的习惯,就是返回带有尾随字符的记录,特别是在我的例子中是\x00。我正在尝试编写一个函数来清理hashref中的所有元素,下面的代码可以做到这一点,但我找不到一种方法来使它更精简,我知道有一种方法可以做得更好:

代码语言:javascript
复制
#!/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;
        }
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-01-25 09:44:59

虽然我认为正则表达式替换并不是一个理想的解决方案(似乎应该正确地解决它),但这里有一个使用chomp解决它的便捷方法。

代码语言:javascript
复制
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只删除字符串末尾的字符,因此更安全。

代码语言:javascript
复制
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;
        }
    }
}
票数 1
EN

Stack Overflow用户

发布于 2012-01-25 09:09:35

首先是你的代码:

代码语言:javascript
复制
   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...

你应该做的是:

代码语言:javascript
复制
foreach my $x (values %$qry) {
    foreach my $y (ref $x eq 'HASH' ? values %$x : $x) {
        $y =~ s/(?:\x00)+$//
    }
}

这将仅清理散列的两个级别的值中的结尾空值。

循环的主体也可以写成:

代码语言:javascript
复制
    if (ref $x eq 'HASH') {
        foreach my $y (values %$x) {
            $y =~ s/(?:\x00)+$//
        }
    }
    else {
        $x =~ s/(?:\x00)+$//
    }

但这会迫使您编写两次替换,并且您不应该重复自己。

或者,如果您真的想减少代码,使用隐式$_变量效果很好:

代码语言:javascript
复制
for (values %$qry) {
    s/(?:\x00)+$// for ref eq 'HASH' ? values %$_ : $_
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8996536

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档