c读取非ASCII字符
我正在解析一个涉及æøå等字符的文件。 如果我们假设我已经存储了一行文本文件,如下所示
#define MAXLINESIZE 1024 char* buffer = malloc(MAXLINESIZE) ... fgets(buffer,MAXLINESIZE,handle) ...
如果我想计算一行中的字符数。 如果我尝试执行以下操作:
char* p = buffer int count = 0; while (*p != '\n') { if (isgraph(*p)) { count++; } p++; }
这忽略了任何æøå的发生
即:计算“aåeæioøu”将返回5而不是8
我是否需要以另一种方式阅读文件? 我不应该使用char*
而是使用int*
吗?
您需要了解哪些编码用于您的角色。 我想这很可能是UTF-8 (你应该到处使用UTF8 ……),阅读Joel关于Unicode的博客 。 如果您的编码不是UTF-8,则应将其转换为UTF-8,例如使用libiconv 。
然后你需要一个用于UTF-8的C库。 它们中有很多(但是C11语言中没有一个是标准化的)。 我推荐libunistring或glib (来自GTK),但也请看这个 。
您的代码将会更改,因为UTF-8字符可能需要一到四[8位]字节(但维基百科UTF-8页面最多提到6个字节;有关详细信息,请参阅Unicode标准)。 你不会测试一个字节(即一个普通的C char
)是否是一个字母,但是如果一个字节和它之后的几个字节(由指针给出,即char*
或更好的uint8_t*
)编码一个字母(包括西里尔字母等。)。
并非每个字节序列都是有效的UTF-8表示,您可能希望在分析之前validation一行(或以空值终止的C字符串)。
C标准IO库只能读取字节 。 您的文件可能包含多字节字符,使用UTF8或其他编码进行编码。 你需要一个库来解释这些文件。
您的文件可能包含Latin1文本,在这种情况下,字符是字节。 在这种情况下,除非您具有正确的区域设置,否则不能使用isgraph
。
底线:找到文件中使用的编码。 然后相应地阅读。 在任何情况下,普通C都不知道编码。
假设你使用UTF-8。
您需要了解UTF-8的工作原理 。
这是一件应该做你想做的工作:
int nbChars(char *str) { int len = 0; int i = 0; int charSize = 0; // Size of the current char in byte if (!str) return -1; while (str[i]) { if (charSize == 0) { ++len; if (!(str[i] >> 7 & 1)) // ascii char charSize = 1; else if (!(str[i] >> 5 & 1)) charSize = 2; else if (!(str[i] >> 4 & 1)) charSize = 3; else if (!(str[i] >> 3 & 1)) charSize = 4; else return -1; // not supposed to happen } else if (str[i] >> 6 & 3 != 2) return -1; --charSize; ++i; } return len; }
它返回字符数,如果它不是有效的UTF-8字符串,则返回-1。
(通过无效的UTF-8字符串,我的意思是格式无效。我不检查字符是否确实存在)
编辑:如评论部分所述,此代码不处理分解的unicode