我正在编写一个从perl结构输出类似于JSON的东西的东西。我希望引用的行为如下:
"string" outputs "string"
"05" outputs "05"
"5" outputs "5"
5 outputs 5
05 outputs 5, or 05 would be acceptable
JSON :: XS通过测试标量是否已经“字符串化”来处理这个问题,我觉得这很酷。但是我没有办法在没有编写XS的情况下自己做这个测试,我宁愿避免。这可能吗?我没有在CPAN的任何地方找到这个,没有找到关于Scalar :: Util :: looks_like_number等的大量迂回,这完全不是我想要的。我能找到的唯一权宜之处是Devel :: Peek,感觉很邪恶。而且,就像JSON :: XS一样,我对这个场景很好:
my $a = 5;
print $a."\n";
# now $a outputs "5" instead of 5)
答案 0 :(得分:5)
use B;
($x, $y, $z) = ("5", 5, 5.0);
print ref(B::svref_2object( \$x )), "\n";
print ref(B::svref_2object( \$y )), "\n";
print ref(B::svref_2object( \$z )), "\n";
输出:
B::PV
B::IV
B::NV
或者,正如池上所说,如果你更愿意查找pPOK
旗帜:
if (B::svref_2object( \$x )->FLAGS & B::SVp_POK) {
print "I guess \$x is stringy\n";
}
答案 1 :(得分:4)
您可以使用以下内容使数字不再显示为字符串:
$x = 0+$x;
例如,
$ perl -MJSON::XS -E'
$_ = 4;
say encode_json([$_]); # [4]
"".$_;
say encode_json([$_]); # ["4"]
$_ = 0 + $_;
say encode_json([$_]); # [4]
'
检测某些内容是否已被字符串化更加困难,因为JSON :: XS正在研究Perl的内部结构。可以使用以下内容:
sub is_stringy {
{ no warnings 'void'; "".$_[0]; }
return 1;
}
但我认为这不是你想要的:)我不知道如何在不编写一些XS代码的情况下检测“损坏”。您想知道的是,标量SvPOKp
是否为真(在标量上调用SvGETMAGIC
之后)。
use Inline C => <<'__EOI__';
SV* is_stringy(SV* sv) {
SvGETMAGIC(sv);
return SvPOKp(sv) ? &PL_sv_yes : &PL_sv_no;
}
__EOI__
$_ = 4;
say is_stringy($_) ?1:0; # 0
{ no warnings 'void'; "".$_; }
say is_stringy($_) ?1:0; # 1
$_ = 0+$_;
say is_stringy($_) ?1:0; # 0
OO!事实证明B确实提供了SVp_POK
,所以它可以(几乎)在不编写新的XS代码的情况下完成
use B qw( svref_2object SVp_POK );
sub is_stringy {
my ($s) = @_;
my $sv = svref_2object(\$s);
#$sv->GETMAGIC(); # Not available
return $sv->FLAGS & SVp_POK;
}
无法拨打SvGETMAGIC
有弊端,但几乎所有时间都可以使用。
答案 2 :(得分:2)
这可能不是最好的方法,但如果JSON
符合您的要求,为什么不使用呢?
sub is_stringy {
encode_json([$_[0]]) =~ /["']/
}
is_stringy(5); # undef
is_string("5"); # 1