【问题标题】:Mapping multibyte characters to their unicode point representation将多字节字符映射到它们的 unicode 点表示
【发布时间】:2011-08-31 18:07:45
【问题描述】:

如何将单个 UTF-8 字符映射到其在 C 中的 unicode 点? [例如,È 将映射到 00c8]。

【问题讨论】:

    标签: c unicode utf-8


    【解决方案1】:

    如果您平台的 wchar_t 存储 unicode(如果它是 32 位类型,它可能会存储)并且您有 UTF-8 语言环境,您可以调用 mbrtowc(来自 C90.1)。

    mbstate_t state = {0};
    wchar_t wch;
    char s[] = "\303\210";
    size_t n;
    memset(&state, 0, sizeof(state));
    setlocale(LC_CTYPE, "en_US.utf8"); /*error checking omitted*/
    n = mbrtowc(&wch, s, strlen(s), &state);
    if (n <= (size_t)-2) printf("%lx\n", (unsigned long)wch);
    

    为了更灵活,可以调用iconv接口。

    char s[] = "\303\210";
    iconv_t cd = iconv_open("UTF-8", "UCS-4");
    if (cd != -1) {
        char *inp = s;
        size_t ins = strlen(s);
        uint32_t c;
        uint32_t *outp = &c;
        size_t outs = 0;
        if (iconv(cd, &inp, &ins, &outp, &outs) + 1 >= 2) printf("%lx\n", c);
        iconv_close(cd);
    }
    

    【讨论】:

    • 感谢您的帖子。我可能想要iconv_t cd = iconv_open("UTF-8", "UCS-2");
    • 你说得对——iconv 标头文档中提到了“UCS-*”。我错过了(我尝试了很多其他组合)。您的回答正是我们所需要的,谢谢。
    【解决方案2】:

    一些值得看的东西:

    • libiconv
    • 转换UTF.h
    • MultiByteToWideChar(windows下)

    【讨论】:

    • 感谢您的帖子。我有点困惑——我认为iconv 是为了改变编码,而不是为了映射到字符串的表示。也许我错过了一些明显的东西。
    • @SK9:字符串的编码是其字符的表示方式,所以我很困惑你在哪里感到困惑。
    • 我没有意识到“UCS-2”可用。
    【解决方案3】:

    UTF-8 到 UCS-2 转换器的相当快速的实现。 BMP 之外的代理和字符作为练习。 该函数返回从输入s 字符串消耗的字节数。负值表示错误。 生成的 unicode 字符被放在p 指向的地址处。

    int utf8_to_wchar(wchar_t *p, const char *s)
    {
    const unsigned char *us = (const unsigned char *)s;
       p[0] = 0;
       if(!*us)
         return 0;
        else 
          if(us[0] < 0x80) {
            p[0] = us[0];
            return 1;
          }
          else 
            if(((us[0] & 0xE0) == 0xC0) && (us[1] & 0xC0) == 0x80) {
              p[0] = ((us[0] & 0x1F) << 6) | (us[1] & 0x3F);
    #ifdef DETECT_OVERLONG
              if(p[0] < 0x80) return -2;
    #endif    
              return 2;
            }
            else 
              if(((us[0] & 0xF0) == 0xE0) && (us[1] & 0xC0) == 0x80 && (us[2] & 0xC0) == 0x80) {
                p[0] = ((us[0] & 0x0F) << 12) | ((us[1] & 0x3F) << 6) | (us[2] & 0x3F);
    #ifdef DETECT_OVERLONG
              if(p[0] < 0x800) return -2;
    #endif    
                return 3;
              }
        return -1;
      }
    

    【讨论】:

    • 我认为您的三字节大小写错误。您需要一直将s 视为unsigned char*,但即便如此,我还是得到0xe201c for (\U{201c})。
    • 哇,我现在明白了 0xe201c 以及为什么它没有在我们的实现中发生。我们有一个 16 位 wchar_t,所以 0xe2 &lt;&lt; 12 溢出了 16 位字,结果是 0x2000 而不是 0xe2000 字。
    • -1 表示接受无效序列的危险代码。除非您知道自己在做什么,否则不要自己动手!
    • 哪些无效序列?它不支持 4 字节序列,也不检查代理空间,但在上面的文本中已经说过。在编译器已过时且系统不提供库(嵌入式系统)的情况下,有时需要实现自己的(有限)版本。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-16
    • 2018-07-23
    • 1970-01-01
    • 2017-03-21
    • 2012-09-29
    • 2011-08-20
    相关资源
    最近更新 更多