為什麼 gawk 在來自輸入數據時將“0123”視為十進制數?
根據
$ 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
八進制數的前導開頭?我懷疑它與strnum 屬性有關,因為出於某種原因1,gawk 將此屬性賦予
0123
但不賦予0x123
:$ awk 'END { print typeof($1) }' <<<'0123' strnum $ awk 'END { print typeof($1) }' <<<'0x123' string
1這可能是由於awk 實現之間的差異:
為了澄清,只有來自幾個來源的字元串(這裡引用 POSIX 規範):
$$ … $$如果它們的值恰好是數字,則將被視為數字字元串(允許前導和尾隨空格, 實現之間的差異以支持 hex、octal、inf、nan…)。
我正在使用 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)
這與
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中定義如下:
輸入字元串被分解為兩部分:一個初始的,可能為空的空白字元序列(由isspace ()指定)和一個被解釋為浮點常量的主題序列。
主題序列的預期形式是可選的
'+'
或'-'
符號,然後是可選的包含 <period> 的非空數字序列,然後是可選的指數部分。指數部分由'e'
or組成'E'
,後跟一個可選的符號,後跟一個或多個十進制數字。以第一個數字或<句點>(以先出現者為準)開始的序列被解釋為C語言的一個浮點常數,如果既沒有出現指數部分也沒有出現<句點>,則假定a跟在最後一個數字後面字元串。如果主題序列以 <hyphen-minus> 開頭,則轉換產生的值被否定。