2012-01-25 5 views
0

DBIを使用してSybaseに接続し、hash_ref要素のレコードを取得しています。私の場合、DBI :: Sybaseドライバは、末尾の文字、特に\ x00でレコードを返すという厄介な癖があります。私はハッシュリファレンスのすべての要素についてこれをクリーンアップする関数を作成しようとしていますが、以下のコードではトリックはしますが、それをもっと痩せる方法は見つけられません。よりよい:Perlハッシュリファレンス代入

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

なぜ値でハッシュキーにアクセスしようとしていますか? '$ qry - > {$ val}'は '代入で初期化されていない値を使う'という警告を出すべきです。 a)警告を使用していない場合、またはb)すべてのキーと同じ値を持つ場合。 – TLP

+0

私は助けることができませんが、これは正規表現でパッチを当てるべきではなく、適切に修正するべきであると感じています。 – TLP

答えて

1

私は正規表現置換が正確に理想的なソリューションではないと思われるものの(それが適切に固定する必要があるように思えます代わりに、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

まず、あなたのコード:

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)+$// 
    } 
} 

のみハッシュの二つのレベルの値にNULLを終了クリーンアップれます。

は、ループの本体は、のように書くこともできます。

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 %$_ : $_ 
} 
関連する問題