Perl Hashref Замены - PullRequest
       2

Perl Hashref Замены

0 голосов
/ 25 января 2012

Я использую DBI для подключения к Sybase, чтобы получить записи в элементе hash_ref. Драйвер DBI :: Sybase имеет неприятную привычку возвращать записи с завершающими символами, в частности, \ x00 в моем случае. Я пытаюсь написать функцию, чтобы очистить это для всех элементов в хэш-функции, код, который у меня есть ниже, делает свое дело, но я не могу найти способ сделать его более компактным, и я знаю, что это еще не решено сделать лучше:

#!/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;
        }

Ответы [ 2 ]

1 голос
/ 25 января 2012

Хотя я думаю, что подстановка регулярных выражений не совсем идеальное решение (похоже, вместо этого оно должно быть исправлено должным образом), вот удобный способ решить эту проблему с помощью 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, который в основном делает то же самое.chomp безопаснее только потому, что удаляет только символы из конца строки, как s/\x00$//.

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 голос
/ 25 января 2012

Сначала ваш код:

   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 %$_ : $_
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...