根据$ man gawk
,该strtonum()
函数可以将字符串转换为数字:
strtonum(str)
检查 str 并返回其数值。如果 str 以前导 0 开头,则将其视为八进制数。如果 str 以前导 0x 或 0X 开头,则将其视为十六进制数。否则,假设它是十进制数。
如果字符串以 开头0
,则该数字被视为八进制,而如果它以 开头,0x
则被视为十六进制。
我运行了这些命令来检查我对该函数的理解:
$ awk 'END { print strtonum("0123") }' <<<''
83
$ awk 'END { print strtonum("0x123") }' <<<''
291
该字符串"0123"
被正确地视为包含八进制数并转换为十进制数83
。同样,字符串"0x123"
被正确地视为包含十六进制数字并转换为十进制数字291
。
现在,如果我运行相同的命令,但将数字字符串从程序文本移动到输入数据,会发生以下情况:
$ awk 'END { print strtonum($1) }' <<<'0123'
123
$ awk 'END { print strtonum($1) }' <<<'0x123'
291
我理解第二个结果与前面的命令相同,但我不理解第一个结果。为什么 gawk 现在将其0123
视为十进制数,即使它以0
表征八进制数的前导开头?
我怀疑这与字符串属性,因为出于某种原因1,gawk 将此属性赋予0123
但不赋予0x123
:
$ awk 'END { print typeof($1) }' <<<'0123'
strnum
$ awk 'END { print typeof($1) }' <<<'0x123'
string
1可能是由于变化awk 实现之间:
为了澄清,只有来自几个来源的字符串(这里引用 POSIX 规范): [...] 如果它们的值恰好是数字(允许前导和尾随空格, 支持十六进制、八进制的实现之间存在差异,inf,南...)。
我正在使用 gawk version 4.2.62
,其输出$ awk -V
是:
GNU Awk 4.2.62, API: 2.0 (GNU MPFR 3.1.4, GNU MP 6.1.0)
答案1
strnum
这与GAWK 4.2 版本中的通用处理有关。
输入值看起来像数字被视为strnum
值,在内部表示为同时具有字符串和数字类型。 “0123”看起来像一个数字,因此它被作为strnum
.strtonum
旨在处理字符串和数字输入;它首先寻找数字,当遇到输入数字时,返回该数字而不进行转换:
NODE *
do_strtonum(int nargs)
{
NODE *tmp;
AWKNUM d;
tmp = fixtype(POP_SCALAR());
if ((tmp->flags & NUMBER) != 0)
d = (AWKNUM) tmp->numbr;
else if (get_numbase(tmp->stptr, tmp->stlen, use_lc_numeric) != 10)
d = nondec2awknum(tmp->stptr, tmp->stlen, NULL);
else
d = (AWKNUM) force_number(tmp)->numbr;
DEREF(tmp);
return make_number((AWKNUM) d);
}
这样“0123”就变成了数字123,直接strtonum
返回。
“0x123”看起来不像一个数字(根据上面给出的链接中定义的规则),因此它被作为字符串处理,并按照您期望的方式进行处理strtonum
。
数字定义如下在 AWK 中:
输入字符串被分解为两部分:一个初始的、可能为空的空白字符序列(由空间()) 和解释为浮点常量的主题序列。
主题序列的预期形式是可选的
'+'
或'-'
符号,然后是可选地包含 <period> 的非空数字序列,然后是可选的指数部分。指数部分由'e'
或组成'E'
,后跟一个可选符号,最后跟一个或多个小数位。以第一个数字或 <period>(以先出现者为准)开始的序列被解释为 C 语言的浮动常量,如果指数部分和 <period> 均未出现,则假定 a 位于最后一位数字之后字符串。如果主题序列以 <hyphen-minus> 开头,则转换产生的值将被否定。