2017-08-02 13 views
3

次のコードでは、クラスをハッシュに結びつけています。Perlでは、JSONエンコーディングの数値と文字列のハッシュ値をどのように区別できますか?

package Example::Tie; 
use JSON; 
my $json = JSON->new(); 

sub TIEHASH { 
    my ($pkg,@list) = @_; 
    bless { @list }, $pkg; 
} 

sub FETCH { 
    my ($tied,$key) = @_; 
    return $json->encode({key => $key}); 
} 

package Example; 

sub new { 
    my ($pkg,@list) = @_; 
    my $self = {}; 
    tie %$self, 'Example::Tie', @list; 
    bless $self, $pkg; 
} 

package main; 
my $exp = Example->new(); 
print($exp->{0} . "\n"); 

私は次のような出力が得られます:0でこれが結果

{"key":"0"} 

文字列としてエンコードされているFETCH機能では、私は、キーのJSONエンコーディングを印刷しています。代わりに番号にエンコードする方法はありますか?

print($exp->{0} . "\n"); # this should print {"key":0} 
print($exp->{'0'} . "\n"); # this should print {"key":"0"} 
+1

関連性:https://metacpan.org/pod/JSON#simple-scalars – simbabque

答えて

5

がPerlで文字列または数値の本当の概念はありませんが、唯一のスカラーので、これはトリッキーです。 。それがコード値を使用した最後のコンテキストを見てそれを行うにJSON module tries

単純なPerlスカラー(リファレンスではない任意のスカラー)をコードするのが最も困難なオブジェクトである:このモジュールは未定義コードしますJSON null値、最後のJSON文字列として符号化前の文字列のコンテキストで使用されているスカラー、および数値として何かのようにスカラー:FETCH

# dump as number 
encode_json [2]      # yields [2] 
encode_json [-3.0e17]    # yields [-3e+17] 
my $value = 5; encode_json [$value] # yields [5] 

# used as string, so dump as string 
print $value; 
encode_json [$value]     # yields ["5"] 

# undef becomes null 
encode_json [undef]     # yields [null] 

あなたのコードは、これを具体的に行いません。だからそれは別の場所になければならない。

私の推測では、ハッシュキーのためのPerlの自動引用がここでの犯人です。

$exp->{0}; # this should print {"key":0} 
$exp->{'0'}; # this should print {"key":"0"} 

これらの2つの式は同等です。 Perlは自動的にハッシュ(ref)要素のために{}の中のものを引用符で囲んだものとして扱い、それらは文字列になります。それは簡単に忘れてしまいますので、there is best practiceは常に一重引用符''を使用してください。

Perldata says(強調鉱山):

ハッシュがキーその関連列によって索引付けスカラー値の順序付けられていないコレクションです。

考えられるのは、ハッシュの数値キーがないことです。数字キーがある場合は、並べ替えることができますし、次に配列があります。

FETCHを引用符で囲まれていない番号で直接呼び出すことで、これをさらに証明することができます。

Example::Tie->FETCH(1); 

これは、明示的に数であるように戻ってそれを強制しようとしない限り、私はので、あなたが何をしたいのかJSONモジュールとtieを使用することは可能ではないと結論

​​ になります。 JSONモジュールのドキュメントには例があります。

あなたはそれをnumifyingによって数になるようにタイプを強制することができます

my $x = "3"; # some variable containing a string 
$x += 0;  # numify it, ensuring it will be dumped as a number 
$x *= 1;  # same thing, the choice is yours. 
+0

この回答ありがとうございました!私は今、 '0'と' '0 'を区別することは不可能であることを見ています。なぜならそれらは両方ともストリング化されているからです。数値キーを扱う際の@SinanÜnürのアプローチを使用します。 – aoiee

+1

@ oaoieeまた、コードを確認する必要があります。変数が実際に値のときに '$ key'と呼ばれるのはなぜですか?関数 'print'を作成して' print'の戻り値を返すのは混乱します。 – simbabque

+0

@simbabqueは、 'FETCH'がJSONでエンコードされた値を出力し、' print'の値を返すのではなく、 'FETCH'を返すべきだと指摘しています。また、 '42.0'にどう対処するのかという問題があります。 –

5

基本的には、@simbabque's answerは上のスポットです。あなたのFETCHが引数リストを取得すると、0$exp->{0}はすでにハッシュキーが文字列であるため、文字列化されています。

もちろん、無差別にフェッチするためにすべての引数に0を追加すると問題が発生します。以下では、数字と文字列を区別するためにScalar::Util::looks_like_numberを使用していますが、"0"で試してみると、これはうまくいきません。それは0にも変換されます。

+0

100kに届きありがとうございます:) – simbabque

関連する問題