【问题标题】:Why is 00 equal to 0 in perl?为什么 00 在 perl 中等于 0?
【发布时间】:2022-01-25 15:34:48
【问题描述】:

我不是一个重度 perl 用户。我只是在学习。但是,最近我正在使用其他人编写的旧脚本。 本质上,该脚本读取一个输入文件,其中定义了变量“index_a”,以便在执行简单打印时:

print "$index_a";
00

我的困惑来自以下几点:

当与“零”进行比较时,它成立:

if ($index_a == 0) { print "Found first index: 0" };
Found first index: 0

我原以为比较是错误的。由于 index_a = 00 的值是通过从输入文件中读取一行获得的。因此,据我了解 index_a 是一个值为“00”的字符串,因此不应执行 if 语句。

perl 专家可以帮助我理解这一点吗?另外,您能否让我知道在 perl 中检查数据类型的正确方法是什么?我有使用 python 和 C 的经验,因此这种行为让我很困惑。

谢谢!

【问题讨论】:

  • == 运算符测试数值相等性。值 00 在数值上等于 0(它们的差为零)。也许您正在寻找eq

标签: perl


【解决方案1】:

在 Perl 中,上下文在考虑值时很重要。标量变量可以包含各种数据类型,但是您要测试的内容决定了您找到的内容。例如:

if ("00" == 0)      # string "00" is numerically identical to 0
if ("a"  == 0)      # string "a" is numerically identical to 0 (gives a warning)
                    # Argument "a" isn't numeric in numeric eq (==)
if ("00" eq "0")    # string "00" is not stringwise identical to "0".
if (@a == 0)        # if the array @a is empty (length 0)

在对字符串进行数值相等检查时,Perl 会尝试将字符串转换为数字。如果字符串以数字开头,它将被强制转换为该数字(在测试期间),否则它将被强制转换为0

当您测试变量包含的内容时,您必须(某种程度上)知道变量中包含的内容。否则你必须更彻底地检查。在您的情况下,从文件读取时,您可能希望使用 eq 来测试字符串是否相等。

【讨论】:

  • 作为旁注,当它以0 开头时,它不会将字符串数字解释为八进制数字,因此"011" != 011' 可能会让人感到意外。
【解决方案2】:

当您在数字上下文中使用 Perl 字符串时,例如数字比较,它会识别看起来像十进制数字的起始部分并忽略之后的内容。无论它识别什么都会成为数字。

它遵循以下基本规则:

  • 忽略前导空格。当您从列数据中提取一个字段并且数字不占用整个列时,这很方便。
  • 允许使用单个前导符号(+-
  • 跳过前导零(所以,没有八进制)
  • 捕获十进制 ASCII 数字(0,1,2,3,4,5,6,7,8,9),允许单个小数点(因此,没有语义版本号)
  • 在第一个非十进制数字字符处停止
  • 到目前为止,您所拥有的就是数字。如果你什么都没有,这个数字就是 0。

不过有几点需要注意:

  • 向字符串添加 0 是强制数字模式的常用方法。
  • 字符串中的下划线只是下划线。您可以使用下划线分隔数字文字中的数字,但不能使用字符串分隔数字。所以,123_456123456,因为 perl 解析器处理 _,但 '123_456' 只是 123
  • 但是,如果第一个字符(不包括符号)是“Inf”,在任何情况下,字符串都会转换为“Inf”并包含- 符号但不包含+ 符号。这是 Infinity 的特殊 IEEE 值。
  • 但是,如果第一个字符(不包括符号)是“NaN”,则在任何情况下,字符串都会转换为“Nan”并排除任何一个符号。这是特殊的“非数字”值。

这里有一些例子:

#!perl
use v5.10;
use utf8;
use open qw(:std :utf8);

my @strings = qw(
    -5 +7 +006 -01 00
    +.1234 -.9876 .657 ..890 1.2.3
    ١٢٣
    - + +-657
    12a34 a987 123fred 0456barney
    0x12 12_34 0177
    NaN -NaN  NAN
    Inf +Inf -Inf INF Infamy Infinity
    );

push @strings, "   432", "+  123", "  -987", "  +063","   NaN", "   Inf", '';

foreach my $string ( @strings ) {
    printf "%-12s => %s\n", qq('$string'), 0 + $string;
    }

然后输出:

'-5'         => -5
'+7'         => 7
'+006'       => 6
'-01'        => -1
'00'         => 0
'+.1234'     => 0.1234
'-.9876'     => -0.9876
'.657'       => 0.657
'..890'      => 0
'1.2.3'      => 1.2
'١٢٣'        => 0
'-'          => 0
'+'          => 0
'+-657'      => 0
'12a34'      => 12
'a987'       => 0
'123fred'    => 123
'0456barney' => 456
'0x12'       => 0
'12_34'      => 12
'0177'       => 177
'NaN'        => NaN
'-NaN'       => NaN
'NAN'        => NaN
'Inf'        => Inf
'+Inf'       => Inf
'-Inf'       => -Inf
'INF'        => Inf
'Infamy'     => Inf
'Infinity'   => Inf
'   432'     => 432
'+  123'     => 0
'  -987'     => -987
'  +063'     => 63
'   NaN'     => NaN
'   Inf'     => Inf
''           => 0

最后,关于 Perl 标量还有一个有趣的地方。当您使用字符串作为数字时,Perl 将字符串转换为数字并记住转换。但是,它不会更改字符串。 Devel::Peek 向您展示 Perl 数据结构的内部结构。

#!perl
use v5.10;
use Devel::Peek;

select(STDERR); $|++; # just to order the output from Dump

my $string = '123fred';
say "string is <$string>";
Dump( $string );

say '-' x 40;

my $n = $string + 0;
say "string is <$string>";
Dump( $string );

这是输出。首先,$string 有一个用于字符串的PV(指针值)。数值运算之后,还有IVNV数值的数值。

string is <123fred>
SV = PV(0x7f8be980cab0) at 0x7f8bea0160f8
  REFCNT = 1
  FLAGS = (POK,IsCOW,pPOK)
  PV = 0x7f8be9610ca0 "123fred"\0
  CUR = 7
  LEN = 10
  COW_REFCNT = 1
----------------------------------------
string is <123fred>
SV = PVNV(0x7f8be980ac50) at 0x7f8bea0160f8
  REFCNT = 1
  FLAGS = (POK,IsCOW,pIOK,pNOK,pPOK)
  IV = 123
  NV = 123
  PV = 0x7f8be9610ca0 "123fred"\0
  CUR = 7
  LEN = 10
  COW_REFCNT = 1

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-28
    • 2011-02-01
    • 2017-06-06
    • 2016-05-03
    • 2012-11-11
    • 1970-01-01
    相关资源
    最近更新 更多