【问题标题】:About awk and integer to ASCII character conversion关于 awk 和整数到 ASCII 字符的转换
【发布时间】:2021-01-26 04:41:06
【问题描述】:

只是为了确定,真的是使用 awk(至少是 Gnu awk)我可以转换吗:

从八进制到ASCII:

print "\101"         # or a="\101"
A

从十六进制到 ASCII:

print "\x41"         # or b="\x41"
B

但是从十进制到 ASCII 我必须:

$ printf "%c\n", 67  # or c=sprintf("%c", 67)
C

我错过的那个 RTFM(备忘录)中没有秘密 print "\?67"

我正在尝试从$0="aabccc" 获取字符频率,例如:

for(i=141; i<143; i++) a=a gsub("\\"i, ""); print a
213

但使用小数(而不是上面示例中的八进制)。十进制方法似乎非常长:

$ cat foo
aabccc
$ awk '{for(i=97;i<=99;i++){c=sprintf("%c",i);a=a gsub(c,"")} print a}' foo
213

它被使用了here

【问题讨论】:

    标签: awk gawk


    【解决方案1】:

    不,\nnn 是八进制,\xnn 是十六进制 - 这就是在字符串中包含不能按原样包含的字符的全部内容,并且您应该始终使用八进制而不是十六进制表示以实现健壮性(请参阅,例如,http://awk.freeshell.org/PrintASingleQuote)。

    我不明白您问题的最后一部分,您在其中陈述了您要对此做什么 - 提供简洁、可测试的示例输入和预期输出,我相信有人可以帮助您以正确的方式做到这一点,不管它是什么。

    这是你想要做的吗?

    $ awk 'BEGIN{for (i=0141; i<0143; i++) print i}'
    97
    98
    

    【讨论】:

    • 显然我也不能让for 使用八进制运行,~ for(i=\141;i&lt;=\143;i++)?
    • 八进制数以0 开头,而不是反斜杠或1。试试awk 'BEGIN{print 0141}' -> 97。您似乎将字符串中 ascii 字符的表示与数字混合在一起。如果您用您正在尝试做的事情(包括示例输入/输出)更新您的问题,我相信您会得到帮助。
    • 你说得对,我已经print "\141" -> a 太多了。谢谢。
    • 好的,我现在明白你在做什么了,你问题中的最后一个脚本是你最好的选择恕我直言,如果你想让它稍微简短一点a=a gsub(sprintf("%c",i),"")
    【解决方案2】:

    查找表是在“仅限 AWK”中解决此问题的唯一方法(直接将 CHAR 转换为 ASCII DECIMAL)。

    您可以简单地使用 sprintf() 将 ASCII DECIMAL 转换为 CHAR。

    • 您可以通过遍历每个已知的 ascii 字符并将它们存储在一个数组中,其中键是字符,值是该字符的 ascii 值。

    • 您可以在 AWK 中使用 sprintf() 来获取每个小数的字符。

    • 然后可以将char传给数组,得到对应的 又是小数。

    在本例中,使用 awk。

    • 我们循环遍历所有 256 个字符,打印出每个字符。
    • 我们将生成的字符串拆分为一系列行,其中每行包含一个字符。
    • 我们在 awk 中构建一个包含 256 个字符(在 BEGIN 中)的表,然后输入每个输入字符以查找每个字符。
    • 最后我们打印出输入中每个字符的代码。
    awk 'BEGIN{
        for(n=0;n<256;n++)
            print sprintf("%c",n)
    }' | awk '{
    for (i=0; ++i <= length($0);)
        printf "%s\n", substr($0, i, 1)
    }' | awk 'BEGIN{
        for(n=0;n<256;n++)
            ord[sprintf("%c",n)]=n
    }{
        print ord[$1]
    }'
    

    也可以反过来,我们查找字符代码列表。

    awk 'BEGIN{
        for(n=0;n<256;n++)
            print sprintf("%s",n)
    }' | awk 'BEGIN{
        for(n=0;n<256;n++)
            char[n]=sprintf("%c",n)
    }{
        print char[$1]
    }'
    

    注意:根据您使用的字符集,第二个示例可能会在高 ascii 范围 (> 128) 内打印出大量垃圾。

    【讨论】:

      【解决方案3】:

      如果正如您在问题末尾所说的那样,您只是想计算字符的频率,我只会组装一个数组。

      $ awk '{for(i=1;i<=length($0);i++) a[substr($0,i,1)]++} END{for(i in a) printf "%d %s\n",a[i],i}' <<<$'aabccc\ndaae'
      1 d
      1 e
      4 a
      1 b
      3 c
      

      请注意,这也支持多行输入。

      我们逐行遍历输入的每一行,递增一个计数器,该计数器是一个以相关字符为键的数组下标。

      我希望这种方法比应用正则表达式来计算每个有趣字符的替换值更有效,但我没有做过任何速度比较测试(当然这取决于你的集合有多大有兴趣)。

      虽然这个答案没有解决您最初的问题,但我希望它能提供一种更好的方法来解决问题。

      (感谢您在问题中提供最后的详细信息。XY problems 在这里太频繁了。)

      【讨论】:

        【解决方案4】:

        注意:根据您使用的字符集,第二个示例可能会在高 ascii 范围 (> 128) 内打印出大量垃圾。

        这可以通过使用 128-255 的八进制代码 \200 - \377 来规避。

        IIRC 字节 C0 C1 F5 F6 F7 F8 F9 FA FB FC FD FE FF 不应存在于正确编码的 UTF-8 文档中(或尚未指定)。 FE 和 FF 可能与 UTF16 字节顺序标记重叠,但由于世界已经标准化为 UTF-8,这在今天几乎不是问题。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-12-13
          • 2014-10-18
          • 1970-01-01
          • 2023-04-06
          • 2020-09-20
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多