为什么 awk 的 printf 将大于 127 的字符值解释为多字节字符?

为什么 awk 的 printf 将大于 127 的字符值解释为多字节字符?

ASCII 字符范围是从 0 到 127,在该范围内,awk 的带有 %c 格式说明符的 printf 输出一个字节的数据:

$ awk 'BEGIN{printf "%c", 97}'
a

$ awk 'BEGIN{printf "%c", 127}' | xxd
00000000: 7f

$ awk 'BEGIN{printf "%c", 127}' | xxd -b
00000000: 01111111

但对于大于 127 的值,它将打印出多个字节:

$ awk 'BEGIN{printf "%c", 128}' | xxd
00000000: c280

$ awk 'BEGIN{printf "%c", 128}' | xxd -b
00000000: 11000010 10000000

0xc280 的意义是什么?为什么 awk 输出该字符而不是 0x80?

答案1

这是UTF-8编码。 11000010开始一个双字节序列(前两位设置后跟一个清零位),有效位为00010000000(第一个字节的最后五位,第二个字节的最后六位),即128 。

AWK 输出此内容是因为您的语言环境设置为使用 UTF-8;您可以切换到非 UTF-8 语言环境来查看差异:

$ LC_ALL=C awk 'BEGIN{printf "%c", 128}' | xxd -b
00000000: 10000000

答案2

让 awk 打印出任意字节的一个技巧是,无论您的语言环境是 UTF8、POSIX 还是 C,都将 256 的大倍数添加到无符号字节条例值中,以使新数字高于0x10FFFFUnicode 14 的限制规格

下面是如何在 gawk 字节模式下访问任意字节以打印出 UTF8 编码字符的演示。同样的方法也可以在 gawk unicode 模式下使用来访问任意字节:

 gawk -e 'BEGIN { printf("%c",50000) }' | od -baxco -t dC

0000000   354 215 220                                                    
           ?  8d  90                                                    
             8dec    0090                                                
          썐  **  **                                                    
           106754  000220                                                
          -20-115-112                                                    
0000003

% gawk -b -e 'BEGIN { printf("%c%c%c",
                             (-20)+8^8,
                            (-115)+8^8,
                            (-112)+8^8) }' | od -baxco -t dC
0000000   354 215 220                                                    
           ?  8d  90                                                    
             8dec    0090                                                
          썐  **  **                                                    
           106754  000220                                                
          -20-115-112                                                    
0000003

% gawk -e 'BEGIN { printf("%c%c%c%c",\
                                      \
                   0xAB+8^8, 0xBA+8^8, \
                   0xCA+8^8, 0xFE+8^8) }' \
 | god --endian=big -baxco -t dCxI

0000000  253  272  312  376
           +    :    J    ~
             abba      cafe
           ?    ?    ?    ?
           125672    145376
         -85  -70  -54   -2
                   abbacafe
0000004

无论您的区域设置如何,此方法都有效。

对于 mawk-1、mawk2-beta 和 nawk,您还可以从无符号字节值中减去 256 并使用printf("%c")负数。 gawk 过去也允许这样做,但最近的版本可能已禁用它。

相关内容