作为一名 C 程序员,我惊讶地发现wc -c
(计算字节数)和wc -m
(计算字符数)对于我的长文本文件输出非常不同的结果。我一直被告知这sizeof(char)
是 1 个字节。
qdii@nomada ~/Documents $ wc -c sentences.csv
102990983 sentences.csv
qdii@nomada ~/Documents $ wc -m sentences.csv
89023123 sentences.csv
有什么解释吗?
答案1
C 中的类型char
是一个字节,但它适用于 ASCII 字符;有可变宽度编码像 UTF-8 这样的编码方式,每个字符占用很多字节。wc
使用该mbrtowc(3)
函数解码多字节序列,具体取决于LC_CTYPE
环境变量设置的区域设置。如果正确设置了区域设置,则在所有情况下都应该得到相同的结果。例如:
qdii@nomada ~/Documents $ LC_CTYPE="C" wc -m sentences.csv
102990983 sentences.csv
答案2
据猜测,
您的区域设置使用 UTF-8 编码,并且
文件中大约 10% 的字符需要多个八位字节才能编码为 UTF-8。
顺便说一下,来自man wc
:
-c, --bytes
print the byte counts
-m, --chars
print the character counts
答案3
最小的例子
考虑 Unicode 字符“é”,称为“带锐音的拉丁文小写字母 E",这是一个带有尖锐的口音用于多种欧洲语言。
它的UTF-8编码是两个字节长“0xc3 0xa9”。
考虑到这一点,我们看到:
printf '\xc3\xa9' | LC_CTYPE=en_US.UTF-8 wc -c
printf '\xc3\xa9' | LC_CTYPE=en_US.UTF-8 wc -m
printf '\xc3\xa9' | LC_CTYPE=C wc -c
printf '\xc3\xa9' | LC_CTYPE=C wc -m
输出:
2
1
2
2
所以我们理解如所解释的https://unix.stackexchange.com/a/51948/32558为了获得正确的 UTF-8 计数,我们需要wc -m
和LC_CTYPE=en_US.UTF-8
。
在我的系统中,如果我使用输入法键入文字 é,结果是相同的:
printf 'é' | LC_CTYPE=en_US.UTF-8 wc -c
在 Ubuntu 21.04 上测试。