我有一个用UTF-8编码的文件,因为它由以下命令显示:
file -i D.txt D.txt: text/plain; charset=utf-8
我只想一个接一个地显示每个角色,所以我这样做了:
FILE * F_entree = fopen("D.txt", "r");
if (! F_entree) usage("impossible d'ouvrir le fichier d'entrée");
char ligne[TAILLE_MAX];
while (fgets(ligne, TAILLE_MAX, F_entree))
{
string mot = strtok(strdup(ligne), "\t");
while (*mot++){printf("%c \n", *mot) ;}
}
但是终端(在Ubuntu 12上)没有很好地显示特殊字符(而是显示<?>
)。我认为问题是只能在%c中存储ASCII码,但是如何显示这些特殊字符呢?
将这些字符保存在内存中的好方法是什么(为了实现树索引)? (我知道最后一个问题不清楚,请不要犹豫要求澄清。)
答案 0 :(得分:2)
它不起作用,因为您的代码将多字节字符拆分为单独的字符。由于您的控制台期望一个有效的多字节代码,在看到第一个代码后,并且它 接收正确的代码,您将得到<?>
- 自由翻译,“whuh?”。它没有收到正确的代码,因为你在那里填充空格和换行符。
如果您以正确的顺序发送正确的代码,您的控制台只能正确解释UTF8字符。算法是:
识别UTF8多字节字符的开头和长度的过程如下:
0x80
的测试足以将它们与UTF8区分开来。110xxxxx
,1110xxxx
,11110xxx
或{{1}位模式之一开始 }。每个唯一的位模式都有一个相关的额外字节数。例如,第一个需要一个附加字节。 111110xx
位与下一个字节的位组合,形成16位或更长的Unicode字符。 (毕竟,这就是UTF8的全部内容。)1111110x
。重要提示:以前模式的 none 以此代码开头!因此,只要您看到任何 UTF8字符,就可以立即显示和所有“下一个”代码,只要它们以位模式开头{ {1}}。这可以使用位掩码高效地进行测试:xxx
,结果应为10xxxxxx
。任何其他值意味着它不再是“下一个”字节,所以你就完成了。
所有这些仅在源文件有效UTF8 时有效。如果你看到一些奇怪的输出,很可能不是。如果您需要检查输入文件的有效性,做需要在Wikipedia页面中实现整个表,并检查每个10......
字节是否实际上后跟一个{{ 1}}字节,依此类推。出现在自身上的模式value & 0xc0
表示错误。
必须阅读的是Joel Spolsky的The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)。有关更多背景信息,另请参阅UTF-8 and Unicode FAQ for Unix/Linux。
我的下面的代码解决了您的一些其他问题。我使用了英文变量名(参见Meta Stackoverflow "Foreign variable names etc. in code")。在我看来0x80
没有必要。此外,110xxxxx
是一个C ++表达式。
我的代码没有“修复”或处理UTF-8打印之外的任何内容。由于您使用10xxxxxx
,因此代码仅在输入文件中每行的第一个10xxxxxx
Tab字符之前打印文本。我假设你知道你在那里做什么; - )
添加。:啊,忘了解决Q2问题,“将这些字符留在内存中的好方法是什么”。 UTF8旨在与C型strdup
字符串最大程度地兼容。您可以安全地存储它们。你不需要做任何特别的事情就可以在支持UTF8的控制台上打印它们 - 好吧,除非你像在这里一样做东西,把它们打印成单独的字符。 string
应该适用于整个单词。
如果你需要知道UTF8的strtok
,\t
和char
,你可以自己编写代码(请参阅上面的维基百科链接)或者找到一个好的预处理制作图书馆。 (我故意遗漏了printf
!)
strcmp