【问题标题】:Delete elements during loop awk semantics在循环 awk 语义期间删除元素
【发布时间】:2022-11-28 18:21:07
【问题描述】:

如果我们假设循环首先返回 k==0(根据规范,此顺序取决于实现)。循环体应该运行多少次?一次还是两次?如果两次应该为 arr[1] 打印什么?

BEGIN {
  arr[0] = "zero"; 
  arr[1] = "one"; 
  for (k in arr) { 
      print "key " k " val " arr[k]; 
      delete arr[k+1]  
  }
}
$ gawk --version
GNU Awk 5.1.0, API: 3.0 (GNU MPFR 4.1.0, GNU MP 6.2.1)
....
$ gawk 'BEGIN { arr[0] = "zero"; arr[1] = "one"; for (k in arr) { print "key " k " val " arr[k]; delete arr[k+1]  } }'
key 0 val zero
key 1 val
$ goawk --version
v1.19.0
$ goawk 'BEGIN { arr[0] = "zero"; arr[1] = "one"; for (k in arr) { print "key " k " val " 
key 0 val zero

gnu-awk 使用arr[1] == "" 运行它两次,而 goawk 运行它一次。 Mawk(mawk 1.3.4 20200120)对键 1,0 进行排序,但具有与 gnu-awk 相同的基本行为,循环两次并为删除的键打印空字符串)。该程序的 posix 定义预期行为是什么?

本质上,在过去的循环中删除的键是否应该出现在未来的循环中?

【问题讨论】:

  • 我不希望有一个不是外部强制执行的一致顺序,比如以整数为键的 for 循环。在 gawk 中,您可以使用“asort”和“asorti”,而不是构建您自己的订单执行代码。我大麦触摸其他人,所以有人必须为他们插话。
  • @tomc 这不是问题。问题是假设如果循环执行两次(即使键 1 在迭代 0 中被删除),键以 0、1 的顺序出现。
  • 对我来说听起来像是未定义的行为。你为什么认为有这方面的规范?
  • @tripleee 这对我来说似乎很合理。我希望听到它是或不是的争论,或者可能是指向我错过的规范的某些部分的链接。
  • 似乎您认为循环应该重新评估数组条件,例如每次迭代的长度,而不是在循环开始时只评估一次。

标签: awk posix semantics


【解决方案1】:

根据the POSIX spec

在这样的 for 循环中向数组添加新元素的结果是 不明确的

但它没有定义如果你删除它们会发生什么,除了:

delete 语句应删除单个数组元素

然而,根据the GNU AWK manual

作为一个信息点,gawk 在循环开始之前设置要迭代的元素列表,并且不更改它。但并非所有 awk 版本都这样做。

所以这个行为是 POSIX 未定义的,是为 GNU AWK 定义的,你必须检查每个其他 AWK 的手册页以了解它的作用。

确定您想要的行为,然后在所有 awk 中稳健且可移植地获得该行为,您可以编写您想要的任何一个:

  1. gawks 行为:
    BEGIN {
      arr[0] = "zero"; 
      arr[1] = "one"; 
      for (k in arr) { 
          indices[k]
      }
      for (k in indices) { 
          print "key " k " val " arr[k]; 
          delete arr[k+1]  
      }
    }
    
    1. goawks 示例中的明显行为:
    BEGIN {
      arr[0] = "zero"; 
      arr[1] = "one"; 
      for ( k in arr ) {
          indices[k]
      }
      for (k in indices) {
          if ( k in arr ) {
              print "key " k " val " arr[k]; 
              delete arr[k+1]  
          }
      }
    }
    

    关于您的代码的一般说明:

    1. for ( k in ... ) 可以按任何顺序访问索引,因此依赖 delete arr[k+1] 删除 arr[] 的元素并不可靠,因为您可能会在循环的第一次迭代中尝试删除超出数组末尾的索引如果 in 决定以 k 开始,则设置为数组中的最后一个索引。
    2. 所有内置和生成的 awk 数组、字段和字符串都从索引 1 开始,而不是 0,所以不要创建自己的从 0 开始的数组,从 1 开始它们以避免必须记住在编写访问索引的代码时它是哪种类型的数组,并且在某些时候不可避免地会被这种差异绊倒。

【讨论】:

    猜你喜欢
    • 2012-01-20
    • 1970-01-01
    • 2019-10-10
    • 2015-05-23
    • 1970-01-01
    • 2013-07-22
    • 1970-01-01
    • 2012-02-15
    • 2011-12-31
    相关资源
    最近更新 更多