为什么 wc -m 和 wc -c 不同?

为什么 wc -m 和 wc -c 不同?

作为一名 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

据猜测,

  1. 您的区域设置使用 UTF-8 编码,并且

  2. 文件中大约 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 -mLC_CTYPE=en_US.UTF-8

在我的系统中,如果我使用输入法键入文字 é,结果是相同的:

printf 'é' | LC_CTYPE=en_US.UTF-8 wc -c

在 Ubuntu 21.04 上测试。

相关内容