我可以确定 awk 变量的类型吗?

我可以确定 awk 变量的类型吗?

我有 awk 的 gawk 版本。在gawk手册的一部分指出awk变量具有“属性”,用于确定在各种操作中如何处理它们。

例如," +3.14"通过解析输入获得的形式的字符串具有该STRNUM属性,这使得它在与数字比较时表现为数字,而 awk 程序中定义的同一字符串不具有该属性。

OTOH,像这样的字符串"3.14"显然具有STRNUM属性,即使它是在程序中定义的,因为代码x = "3.14" { print x == 3.14 }打印 1。而如果我们将其定义为"+3.13"or " 3.14",它就没有STRNUM属性,因为x = "+3.14" { print x == 3.14 }orx = " 3.14" { print x == 3.14 }打印 0。

我认为变量类型的这种简洁性可能会导致微妙的错误。因此,为了帮助调试这种情况,有没有办法了解变量具有什么类型的“属性”?即,我们能知道变量的类型是什么吗?

答案1

awk 有4种:“数字”、“字符串”、“数字字符串”和“未定义”。这是一个函数检测到:

function o_class(obj,   q, x, z) {
  q = CONVFMT
  CONVFMT = "% g"
    split(" " obj "\1" obj, x, "\1")
    x[1] = obj == x[1]
    x[2] = obj == x[2]
    x[3] = obj == 0
    x[4] = obj "" == +obj
  CONVFMT = q
  z["0001"] = z["1101"] = z["1111"] = "number"
  z["0100"] = z["0101"] = z["0111"] = "string"
  z["1100"] = z["1110"] = "strnum"
  z["0110"] = "undefined"
  return z[x[1] x[2] x[3] x[4]]
}

对于 的第三个参数split,您需要的不是空格,也不是 的一部分,obj否则它将被视为分隔符。我选择\1 基于斯蒂芬的建议。该函数进行内部CONVFMT 切换,因此无论CONVFMT函数调用时的值如何,它都应该返回正确的结果:

split("12345.6", q); print 1, o_class(q[1])
CONVFMT = "%.5g"; split("12345.6", q); print 2, o_class(q[1])
split("nan", q); print 3, o_class(q[1])
CONVFMT = "%.6G"; split("nan", q); print 4, o_class(q[1])

结果:

1 strnum
2 strnum
3 strnum
4 strnum

完整的测试套件:

print 1, o_class(0)
print 2, o_class(1)
print 3, o_class(123456.7)
print 4, o_class(1234567.8)
print 5, o_class(+"inf")
print 6, o_class(+"nan")
print 7, o_class("")
print 8, o_class("0")
print 9, o_class("1")
print 10, o_class("inf")
print 11, o_class("nan")
split("00", q); print 12, o_class(q[1])
split("01", q); print 13, o_class(q[1])
split("nan", q); print 14, o_class(q[1])
split("12345.6", q); print 15, o_class(q[1])
print 16, o_class()

结果:

1 number
2 number
3 number
4 number
5 number
6 number
7 string
8 string
9 string
10 string
11 string
12 strnum
13 strnum
14 strnum
15 strnum
16 undefined

值得注意的弱点是:如果您提供以下任何一个“数字字符串”,该函数将错误地返回“数字”:

  • 整数
  • inf
  • -inf

对于整数,解释如下:

完全等于整数值的数值应通过等效于以sprintf字符串%d作为fmt参数调用函数来转换为字符串

然而,inf-inf应该这样做;也就是说,上述各项都不会受到该CONVFMT变量的影响:

CONVFMT = "% g"
print "" .1
print "" (+"nan")
print "" 1
print "" (+"inf")
print "" (+"-inf")

结果:

 0.1
 nan
1
inf
-inf

实际上这并不重要,请参阅鸭子测试

答案2

从 GNU Awk 4.2 开始,有一个新函数typeof()可以检查这一点,如测试版本的发行说明中所示:

  1. 新的 typeof() 函数可用于指示变量或数组元素是否为数组、正则表达式、字符串或数字。 isarray() 函数已被弃用,取而代之的是 typeof()。

所以现在你可以说:

$ awk 'BEGIN {print typeof("a")}'
string
$ awk 'BEGIN {print typeof(1)}'
number
$ awk 'BEGIN {print typeof(a[1])}'
unassigned
$ awk 'BEGIN {a[1]=1; print typeof(a)}'
array
$ echo ' 1 ' | awk '{print typeof($0)}'
strnum

答案3

与 gawk 一样,PROCINFO["identifiers"]包含变量信息的数组。像这样使用它:PROCINFO["identifiers"]["your_variable_name"].返回的可能值是“数组”、“内置”、“扩展”、“标量”、“无类型”、“用户”之一。

只有一个 General scalar,其中包括字符串和数字。口译gawk员只是尽力做事。

variable + 0有时您会在某处看到看似多余的变量,以确保awk将变量视为数字变量,这是有原因的。

请参阅本段了解一些隐式转换的诡计

答案4

如果gawk < 4.2(RHEL7默认版本:gawk 4.0.2)
作为 fedorqui 答案和 gawk 4.2发行公告

14. 新的 typeof() 函数可用于指示变量或数组元素是否为数组、正则表达式、字符串或数字。

$ cat test.txt 
11.11
-0
ext4
0
xfs
0.123
11111.111111
-3333.3333333

$ cat test.txt | awk '{if($1!=0 && $1+0==0) {print $1" non-numeric"} else {print $1" numeric"} }'
11.11 numeric
-0 numeric
ext4 non-numeric
0 numeric
xfs non-numeric
0.123 numeric
11111.111111 numeric
-3333.3333333 numeric

如果呆呆> = 4.2

$ cat test.txt | awk '{{print $1" ,"typeof($1)}}'
11.11 ,strnum
-0 ,strnum
ext4 ,string
0 ,strnum
xfs ,string
0.123 ,strnum
11111.111111 ,strnum
-3333.3333333 ,strnum

相关内容