Perl通常透明地将数字转换为字符串值,反之亦然。然而,必须有一些允许例如Data::Dumper
区分两者,如本例所示:
use Data::Dumper;
print Dumper('1', 1);
# output:
$VAR1 = '1';
$VAR2 = 1;
是否有Perl函数允许我以类似的方式区分标量的值是存储为数字还是字符串?
答案 0 :(得分:17)
标量有许多不同的字段。使用Perl 5.8或更高版本时,Data :: Dumper会检查IV(整数值)字段中是否有任何内容。具体来说,它使用类似于以下内容的东西:
use B qw( svref_2object SVf_IOK );
sub create_data_dumper_literal {
my ($x) = @_; # This copying is important as it "resolves" magic.
return "undef" if !defined($x);
my $sv = svref_2object(\$x);
my $iok = $sv->FLAGS & SVf_IOK;
return "$x" if $iok;
$x =~ s/(['\\])/\\$1/g;
return "'$x'";
}
您可以使用类似的技巧。但请记住,
在不丢失的情况下对浮点数进行字符串化非常困难。 (浮动指针编号使用$sv->FLAGS & SVf_NOK
标识。)
您需要正确转义字符串文字中的某些字节(例如NUL)。
标量可以存储多个值。例如,!!0
包含一个字符串(空字符串),一个浮点数(0
)和一个有符号整数(0
)。如您所见,不同的值甚至不等同。有关更具戏剧性的示例,请查看以下内容:
$ perl -E'open($fh, "non-existent"); say 0+$!; say "".$!;'
2
No such file or directory
答案 1 :(得分:15)
它更复杂。 Perl根据变量的使用上下文更改变量的内部表示:
perl -MDevel::Peek -e '
$x = 1; print Dump $x;
$x eq "a"; print Dump $x;
$x .= q(); print Dump $x;
'
SV = IV(0x794c68) at 0x794c78
REFCNT = 1
FLAGS = (IOK,pIOK)
IV = 1
SV = PVIV(0x7800b8) at 0x794c78
REFCNT = 1
FLAGS = (IOK,POK,pIOK,pPOK)
IV = 1
PV = 0x785320 "1"\0
CUR = 1
LEN = 16
SV = PVIV(0x7800b8) at 0x794c78
REFCNT = 1
FLAGS = (POK,pPOK)
IV = 1
PV = 0x785320 "1"\0
CUR = 1
LEN = 16
答案 2 :(得分:10)
使用纯perl无法找到它。 Data :: Dumper使用C库来实现它。如果强制使用Perl,如果它们看起来像十进制数字,它就不会区分字符串。
use Data::Dumper;
$Data::Dumper::Useperl = 1;
print Dumper(['1',1])."\n";
#output
$VAR1 = [
1,
1
];
答案 3 :(得分:6)
根据您的评论,这是为了确定SQL语句是否需要引用,我会说正确的解决方案是使用占位符,这在DBI文档中有描述。
通常,您不应直接在查询字符串中插入变量。
答案 4 :(得分:4)
autobox::universal
附带的use autobox::universal qw(type);
say type("42"); # STRING
say type(42); # INTEGER
say type(42.0); # FLOAT
say type(undef); # UNDEF
模块提供autobox功能,可用于此目的:
{{1}}
答案 5 :(得分:3)
当变量用作数字时,会导致变量在后续上下文中被假定为数字。但是,反过来并不完全正确,如下例所示:
use Data::Dumper;
my $foo = '1';
print Dumper $foo; #character
my $bar = $foo + 0;
print Dumper $foo; #numeric
$bar = $foo . ' ';
print Dumper $foo; #still numeric!
$foo = $foo . '';
print Dumper $foo; #character
有人可能期望第三个操作将$foo
放回字符串上下文中(反转$foo + 0
),但事实并非如此。
如果您想检查某些内容是否为数字,标准方法是使用正则表达式。您检查的内容因您希望的数字类型而异:
if ($foo =~ /^\d+$/) { print "positive integer" }
if ($foo =~ /^-?\d+$/) { print "integer" }
if ($foo =~ /^\d+\.\d+$/) { print "Decimal" }
等等。
检查内部存储的内容通常没有用处 - 您通常不需要担心这一点。但是,如果你想复制Dumper在这里做什么,那就没问题了:
if ((Dumper $foo) =~ /'/) {print "character";}
如果Dumper的输出包含单引号,则表示它显示的是以字符串形式表示的变量。
答案 6 :(得分:3)
您可能想尝试Params::Util::_NUMBER
:
use Params::Util qw<_NUMBER>;
unless ( _NUMBER( $scalar ) or $scalar =~ /^'.*'$/ ) {
$scalar =~ s/'/''/g;
$scalar = "'$scalar'";
}
答案 7 :(得分:2)
一个未提及的简单解决方案是Scalar :: Util的looks_like_number。 Scalar :: Util是5.7.3以来的核心模块,而Looks_like_number使用perlapi来确定标量是否为数字。
答案 8 :(得分:0)
我不认为有perl函数可以找到值的类型。可以找到DS的类型(标量,数组,哈希)。可以使用正则表达式来查找值的类型。