使用C在终端中打印多字节字符

时间:2014-06-01 19:59:17

标签: c encoding utf-8 terminal

我一直在试验一个自定义字符串对象(struct),如下所示:

typedef struct
{
    int encoding;
    int length;
    character * array;
} EncodedString;

我的想法是,通过指定编码,我可以制作一些使用该编码正确打印字符串的函数,即ASCII或utf-8或utf-16等。(请原谅我的字符编码无知。)< / p>

现在,我正打算打印出一个(普通话)汉字:狗(0x72d7)。我想也许是通过逐个字符打印它,它会正常工作,但显然不是。它打印只是“r?” (分别为0x72和0xd7)。那么如何修改这个程序以便它打印出角色?

#include <stdio.h>

typedef unsigned char character;

typedef struct
{
    int encoding;
    int length;
    character * array;
} EncodedString;

void printString(EncodedString str);

int main(void)
{

    character doginmandarin[] = {0x72U, 0xd7U};
    EncodedString mystring = {0, sizeof doginmandarin, doginmandarin};

    printString(mystring);
    printf("\n");

    return 0;

}

void printString(EncodedString str) // <--- where I try to print the character
{
    int i;
    for(i = 0; i < str.length; i++)
    {
        printf("%c", str.array[i]);
    }
}

理想情况下,我更喜欢包含字符的数组只包含无符号字符,这意味着将构成字符狗的两个字节分开。虽然它现在没有任何用途,但我们的想法是使用encoding结构的EncodedString字段来确定每个字符的字节数。

如何用最少量的黑客来实现?

2 个答案:

答案 0 :(得分:3)

您应该查看与宽字符(wchar_t)和多字节字符串有关的c库函数。 Linux上的c-library实现(或者据我所知的windows)与unicode兼容。 (如果你需要在你的微控制器板上使用它,你可能会运气不好)。大多数处理utf-8编码和unicode的东西都已存在,所以你不需要自己动手。 这是一个如何处理一个角色的例子:

#include <stdio.h>
#include <locale.h>
#include <wchar.h>

int main ()
{
  /*
   * use an utf-8 compatible locale.
   */
  setlocale (LC_ALL, "en_US.utf8");
  const wchar_t dog = 0x72d7;

  /*
   * wchar_t strings can contain any character. Create one
   * string containing only the dog.
   */
  wchar_t in[2] = { dog, 0 };
  char out[100];
  /*
   * convert to a multibyte string, returns the number of chars.
   */
  size_t len = wcstombs (out, in, sizeof out);

  printf ("the character '%lc' is %zd bytes (string: '%s')\n", dog, len, out);
}

输出:

$ ./a.out 
the character '狗' is 3 bytes (string: '狗')

答案 1 :(得分:1)

数字Ox72d7是您要打印的字符的Unicode代码点(摘要编号)。当在内存中用两个字节0x72, 0xd7表示时,它就成为该字符的UCS-2代码,它也恰好是它的UTF-16编码。但是您的终端可能期望UTF-8编码字符。代码点Ox72d7的正确UTF-8编码为0xe7, 0x8b, 0x97

您可以修复代码以使用UTF-8编码字符,但这种编码对于内存表示非常不切实际,因为它会为不同的字符生成不同数量的字节。这使得简单的字符串操作比如使第n个字符非常复杂。相反,经常使用固定长度的表示。例如,UCS-2每个字符总是使用两个字节。然后,在打印字符串之前,尽可能晚地完成到外部表示编码的转换。

编辑(来自评论)

UTF-8是一种棘手的编码。从代码点到UTF-8字节的映射并不简单,涉及一些按位的mumbo-jumbo。它是一种霍夫曼代码,不同的前缀表示字符占用的字节数。此外,所有后续字节都以0b10开头,以便检测格式错误的UTF-8。这里描述了:http://en.wikipedia.org/wiki/UTF-8#Description

为了快速找到我的帖子的三个字节,我只需在python控制台中输入:u"\u72d7".encode('UTF-8')