【问题标题】:loop over characters in input string using awk使用 awk 循环输入字符串中的字符
【发布时间】:2012-01-23 17:25:07
【问题描述】:

信不信由你,我找不到我认为这个非常基本的问题的答案。

在 awk 中,如何逐个字符地循环输入字符串?假设我只是想将它们打印出来。有我可以访问的数组吗?还是我需要使用 substr?

基本上是这样的:

echo "here is a string" | awk '
{ for(i=0; i<[length of input string]; i++) 
    printf [value at index i in array x]; 
}'

坦率地说,我很尴尬。

【问题讨论】:

    标签: string for-loop awk


    【解决方案1】:

    您可以使用split 将字符串转换为数组:

    echo "here is a string" | awk '
    { 
      split($0, chars, "")
      for (i=1; i <= length($0); i++) {
        printf("%s\n", chars[i])
      }
    }'
    

    这会垂直打印字符,每行一个。

    【讨论】:

    • 实际上,length() 是一个 gawk 扩展 AFAIK,它不适用于纯 awk stackoverflow.com/questions/14720898/…
    • @vaxquis 我不确定你所说的“纯”awk 是什么意思,但length 在 POSIX 中。 gawk 扩展适用于数组而不是字符串。幸运的是,我们可以将length(chars) 切换为length($0)
    • "pure" awk 在“不是任何扩展的 awk”的意义上......是的,我的意思是 length();此外,您可以使用 "len = split(...)" 和稍后的 "i
    • 还有一个问题 - 这显然忽略了输入中的空格 - 有没有办法拆分数据,以便我真正知道空格在哪里?还是我必须分别解析每个“记录”(行)才能做到这一点?
    【解决方案2】:

    并非所有 awk 实现都支持上述解决方案。 在这种情况下,您可以使用 substr:

    echo here is a string | awk '{
      for (i=0; ++i <= length($0);) 
        printf "%s\n", substr($0, i, 1)
      }'
    

    附:在一些 awk 实现中,不带参数的长度默认为 $0, 即 lengthlength($0) 是等价的。

    【讨论】:

      【解决方案3】:

      默认情况下,awk 中的Field Separator (FS)spacetabs。既然你提到你想遍历每个字符而不是单词,我们将不得不将 FS 重新定义为空。像这样的 -

      [jaypal:~/Temp] echo "here is a string" | awk -v FS="" '
      {for (i=1;i<=NF;i++) printf "Character "i": " $i"\n"}' 
      Character 1: h
      Character 2: e
      Character 3: r
      Character 4: e
      Character 5:  
      Character 6: i
      Character 7: s
      Character 8:  
      Character 9: a
      Character 10:  
      Character 11: s
      Character 12: t
      Character 13: r
      Character 14: i
      Character 15: n
      Character 16: g
      

      【讨论】:

      • 嗯。实际上,当在代码中设置 FS 时它可以工作,但方式有点不同......(例如,第一行没有被解析)有什么想法吗?
      • 这是因为第一行之前已经用默认FS读取了。
      • @vaxquis 你必须在 BEGIN 开始:'BEGIN {FS="";}'
      • @vaxquis 在代码之外或在BEGIN 中设置FS 是一回事。 BEGIN 块在读取输入的第一行之前只读取一次。
      • 请注意,在 awk 的许多实现中,空 FS 的行为是未定义的:stackoverflow.com/questions/22044272/…
      【解决方案4】:

      如果你有傻瓜:

      awk '$0=gensub(/(.)/,"\\1\n","g")' file
      

      测试:

      kent$  echo "I am a String"|awk '$0=gensub(/(.)/,"\\1\n","g")'
      I
      
      a
      m
      
      a
      
      S
      t
      r
      i
      n
      g
      

      【讨论】:

      • 有没有办法使用这种方法对每个字符做一些事情,还是只是重新格式化字符串?
      • 它可以“对每个字符做一些事情”。但这取决于什么是“东西”
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-05-07
      • 2022-06-27
      • 2017-08-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多