我正在尝试使用我自己的wc版本(unix过滤器),但是我遇到了非ASCII字符的问题。我做了一个文本文件的HEX转储,发现这些字符占用了多个字节。所以他们不适合char。有没有什么办法可以从文件中读取这些字符,并像C中的单个字符(为了计算文件中的字符数)一样处理它们? 我一直在谷歌搜索并找到一些wchar_t类型,但没有任何简单的例子如何将它与文件一起使用。
答案 0 :(得分:8)
我一直在谷歌搜索并找到一些wchar_t类型,但没有任何简单的例子如何将它与文件一起使用。
很满意。没有任何简单的例子,因为不幸的是,正确的字符集支持并不简单。
除此之外:在一个理想的世界中,每个人都会使用UTF-8(一种具有内存效率,健壮且向后兼容ASCII的Unicode编码),标准C库将包括UTF-8编码 - 解码支持,这个问题的答案(以及一般的文本处理)将简单明了。
问题“What is the best unicode library for C?”的答案是使用ICU库。您可能需要查看ustdio.h,因为它具有u_fgetc
功能,并且为您的程序添加Unicode支持可能只需输入u_
几次就可以了。
另外,如果你可以花几分钟时间阅读一些内容,你可能需要阅读Joel On Software的The Absolute Minimum Every Software Developer Absolutely, Positively Must Know about Unicode and Character Sets (No Excuses!)。
我个人从未使用过ICU,但从现在开始我可能会这样做: - )
答案 1 :(得分:4)
如果要在运行时编写一个尊重当前语言设置的wc
实用程序的标准C版本,那么您确实可以使用stdio函数的wchar_t
版本。在程序启动时,您应该致电setlocale()
:
setlocale(LC_CTYPE, "");
这将使宽字符函数使用由环境定义的适当字符集 - 例如。在类Unix系统上,LANG
环境变量。例如,这意味着如果您的LANG
变量设置为UTF8
语言环境,则宽字符函数将处理UTF8中的输入和输出。 (这是指定POSIX wc
实用程序的工作方式。)
然后,您可以使用所有标准功能的宽字符版本。例如,如果你有这样的代码:
long words = 0;
int in_word = 0;
int c;
while ((c = getchar()) != EOF)
{
if (isspace(c))
{
if (in_word)
{
in_word = 0;
words++;
}
}
else
{
in_word = 1;
}
}
...您可以将c
更改为wint_t
,getchar()
更改为getwchar()
,EOF
更改为{{} 1}}和WEOF
到isspace()
:
iswspace()
答案 2 :(得分:2)
去看看ICU。该库是您处理所有问题所需的。
答案 3 :(得分:1)
到目前为止,大多数答案都有其优点,但您使用的答案取决于您想要的语义:
getwchar()
就可以了。mbrtowc
。00-7F
和C2-F4
中的字节并跳过计算所有其他字节,但这可能会在存在时产生错误的结果无效的序列。一种更强大的方法是将字节流解码为Unicode代码点并计算成功解码的数量。希望这有帮助。
答案 4 :(得分:0)
您确定您确实需要字符的数量吗? wc
计算字节数。
~$ echo 'דניאל' > hebrew.txt
~$ wc hebrew.txt
1 1 11 hebrew.txt
(11 = 5个双字节字符+ 1个字节代表'\ n')
但是,如果你确实想要计算字符数而不是字节数,并且可以假设你的文本文件是用UTF-8编码的,那么最简单的方法是计算所有不是的字节跟踪字节(即,在0x80到0xBF范围内)。
如果你不能假设UTF-8但可以假设任何非UTF-8文件采用单字节编码,那么执行UTF- 8验证检查数据。如果通过,则返回UTF-8前导字节数。如果失败,则返回总字节数。
(请注意,上述方法仅适用于wc
。如果您实际上正在使用字符进行某些操作而不是仅计算它们,则需要知道编码。 )