我是不是发现了一个 awk 错误?

我是不是发现了一个 awk 错误?

使用测试2.txt

$ cat /tmp/test2.txt | hexdump -C
00000000  47 61 6c 6c 6f 20 63 65  6c 74 69 63 6f 0a 47 65  |Gallo celtico.Ge|
00000010  73 97 20 42 61 6d 62 69  6e 6f 0a                 |s. Bambino.|

以下是发生的事情awk

$ cat /tmp/test2.txt | awk '/\x97/{print}'
Ges Bambino

$ cat /tmp/test2.txt | awk '/[\x7F-\xFF]/{next;}; 1'
Gallo celtico
Ges Bambino

即,行Ges Bambinoline 包含一个字符\x97,并awk确认了第一个命令中的 。但是,\x97处于 的范围内\x7F-\xFF,因此第二个命令中应该跳过该行,但事实并非如此。

在我看来这确实是一个awk错误。
有什么评论吗?

PS.使其更加明显:

$ cat /tmp/test2.txt | awk '/\x97/{next}; 1'
Gallo celtico

$ cat /tmp/test2.txt | awk '/[\x97]/{next}; 1'
Gallo celtico
Ges Bambino

更新:

正如@KamilMaciorowski 指出的那样,它与本地相关。即上述情况发生在

$ set | egrep '^LANG|^LC'
LANG=zh_CN.UTF-8

而两者

cat /tmp/test2.txt | LC_ALL=C awk '/[\x97]/{next}; 1'
cat /tmp/test2.txt | LC_ALL=C awk '/[\x7F-\xFF]/{next;}; 1'

给出了正确的结果。

但这是一个问题,不是吗?

答案1

C字节和字符仅在默认(又名)语言环境中相同POSIX,但在所有其他语言环境中它们都不同。因此,如果您的系统默认使用 UTF-8 语言环境(例如en_US.UTF-8),则 gawk 正则表达式中括号中的“字符类”基于人物,而不是单个字节。

例如,/[eęė]/相当于/[e\xC4\x99\xC4\x97]/假设一个 *.UTF-8 语言环境;但是,它将匹配字母,ę但不匹配č,尽管两者都有一个C4字节。(出于某种原因,这与普通的/\xC4/ 外部一个字符类,匹配文字字节C4。)

无论如何,这同样适用于字符类内的范围,并且由于字节FF不能构成有效的 UTF-8 序列,因此正则表达式库可能只是将整个范围声明为无效或其他。

gawk 有一个-b,--characters-as-bytes选项可以禁用此功能。

相关内容