Linux终端中未正确显示特殊字符

时间:2014-08-02 16:46:15

标签: c character-encoding

我有一个用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码,但是如何显示这些特殊字符呢?

将这些字符保存在内存中的好方法是什么(为了实现树索引)? (我知道最后一个问题不清楚,请不要犹豫要求澄清。)

1 个答案:

答案 0 :(得分:2)

它不起作用,因为您的代码将多字节字符拆分为单独的字符。由于您的控制台期望一个有效的多字节代码,在看到第一个代码后,并且它 接收正确的代码,您将得到<?> - 自由翻译,“whuh?”。它没有收到正确的代码,因为你在那里填充空格和换行符。

如果您以正确的顺序发送正确的代码,您的控制台只能正确解释UTF8字符。算法是:

  1. 下一个字符是UTF-8序列的起始代码吗?如果没有,请打印并继续。
  2. 如果是,请打印并打印此角色的​​所有“下一个”代码。有关实际编码,请参阅Wikipedia on UTF8;我在下面的代码中选择了一个快捷方式。
  3. 然后才打印您的空间(..?)和换行符。
  4. 识别UTF8多字节字符的开头和长度的过程如下:

    1. “常规”(ASCII)字符永远不会设置第7位。针对0x80的测试足以将它们与UTF8区分开来。
    2. 每个UTF8字符序列以<{1}},110xxxxx1110xxxx11110xxx或{{1}位模式之一开始 }。每个唯一的位模式都有一个相关的额外字节数。例如,第一个需要一个附加字节。 111110xx位与下一个字节的位组合,形成16位或更长的Unicode字符。 (毕竟,这就是UTF8的全部内容。)
    3. 每个下一个字节 - 无论多少! - 具有位模式1111110x。重要提示:以前模式的 none 以此代码开头!
    4. 因此,只要您看到任何 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\tchar,你可以自己编写代码(请参阅上面的维基百科链接)或者找到一个好的预处理制作图书馆。 (我故意遗漏了printf!)

      strcmp