我正在尝试使用JSON::XS
将数据从Perl哈希导出到Python字典。我想将数字导出为数字(而不是unicode文本)。但似乎在一个案例中很难实现:
use Data::Dump qw(dump);
use JSON::XS;
my $h={a=> 1};
dump($h);
my $js = encode_json $h;
print "$js\n";
这将数字1作为字符串输出:(输出为)
{ a => 1 }
{"a":"1"}
但仅限于我使用Data:Dump::dump
。如果我删除了行dump($h)
,则会给出
{"a":1}
我期望(和需要)的输出。
我在Ubuntu 12.04上使用Perl版本5.14和5.16对此进行了测试。
答案 0 :(得分:2)
Perl标量可以是多种内容,并根据它们的使用方式在各种事物之间自动转换。您可以使用Devel::Peek查看您正在处理的内容。这是一个例子。
use strict;
use warnings;
use Devel::Peek ();
my $h = { foo => 42 };
Devel::Peek::Dump( $h );
<强>输出强>
SV = IV(0x7fd5520291e8) at 0x7fd5520291f8
REFCNT = 1
FLAGS = (PADMY,ROK)
RV = 0x7fd552003438
SV = PVHV(0x7fd552008d20) at 0x7fd552003438
REFCNT = 1
FLAGS = (SHAREKEYS)
ARRAY = 0x7fd551e003f0 (0:7, 1:1)
hash quality = 100.0%
KEYS = 1
FILL = 1
MAX = 7
Elt "foo" HASH = 0xa8c24522
SV = IV(0x7fd5520289f0) at 0x7fd552028a00
REFCNT = 1
FLAGS = (IOK,pIOK)
IV = 42
这是关于我们的匿名哈希的一大堆内部信息,但重要的一点是在最后一行,这是一组描述哈希元素foo
的东西。它显示IV = 42
,表示此标量(与foo
关联的哈希值)是 I nteger V alue。
如果我们首先通过Data::Dump
运行会发生什么?
use strict;
use warnings;
use Devel::Peek ();
use Data::Dump ();
my $h = { foo => 42 };
Data::Dump::dump( $h );
Devel::Peek::Dump( $h );
<强>输出强>
SV = IV(0x7fce39829230) at 0x7fce39829240
REFCNT = 1
FLAGS = (PADMY,ROK)
RV = 0x7fce39803438
SV = PVHV(0x7fce39808d20) at 0x7fce39803438
REFCNT = 1
FLAGS = (OOK,SHAREKEYS)
AUX_FLAGS = 0
ARRAY = 0x7fce3940a340 (0:7, 1:1)
hash quality = 100.0%
KEYS = 1
FILL = 1 (cached = 0)
MAX = 7
RITER = -1
EITER = 0x0
RAND = 0x3bebb965
Elt "foo" HASH = 0x525af8b0
SV = PVIV(0x7fce3982b238) at 0x7fce39828a00
REFCNT = 1
FLAGS = (IOK,POK,pIOK,pPOK)
IV = 42
PV = 0x7fce39430e20 "42"\0
CUR = 2
LEN = 16
通过Data::Dump
运行,我们的哈希变化了很多。特别地,散列值42现在具有称为PV
的字段,其是字符串"42"
。那是因为当你有一个包含数字的标量,并且你在期望字符串的上下文中使用它时,Perl会默默地将它转换为字符串类型。 (实际上,这是一个偶数的specialer类型,它同时包含一个字符串和一个数字。如果你真的想让人们出来,你甚至可以让它们成为different things。)
所以Data::Dump
已经导致你的数字被字符串化了,JSON::XS
看起来很糟糕,看看每个标量是什么样的,将它解释为字符串。
所以有几个选择。
选择第一个
在使用Data::Dump
之前获取您的JSON字符串。这可能是最简单的。
选择第二个
在序列化为JSON之前为每个数值添加零,这会强制它们进入数字上下文。
use strict;
use warnings;
use 5.010;
use JSON::XS;
my %h;
$h{a} = "42";
say encode_json( \%h );
$h{a} += 0;
say encode_json( \%h );
<强>输出强>
{"a":"42"}
{"a":42}
有关JSON :: XS如何处理序列化启发式的更多信息,请参阅文档:
答案 1 :(得分:1)
似乎问题已在Data::Dump
Bug #86592 for Data-Dump: undesirable change of SV flags。
问题是source中的以下行:
elsif (do {no warnings 'numeric'; $$rval + 0 eq $$rval}) {
更改整数的标志,使JSON :: XS认为它是一个字符串。
(模块何时会修复bug修复?有人知道吗?)