Input

為什麼 gawk 在來自輸入數據時將“0123”視為十進制數?

  • February 26, 2019

根據$ 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)

這與strnumGAWK 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> 開頭,則轉換產生的值被否定。

引用自:https://unix.stackexchange.com/questions/503133