开发者社区 问答 正文

mbtowc 函数中如何计算最终的 Unicode 值?

mbtowc 函数中如何计算最终的 Unicode 值?

展开
收起
花开富贵111 2024-06-17 19:08:04 42 分享 版权
1 条回答
写回答
取消 提交回答
  • 通过 & Unicode有效值掩码,移除高位前缀码,得到最终unicode值

    如下代码所示:

    typedef struct
    {
      int cmask; //前缀码掩码
      int cval;  //前缀码
      int shift; //移动位数
      long lmask; //Unicode值掩码
      long lval;  //Unicode下限值
    } Tab;
    
    static Tab  tab[] =
    {
      0x80, 0x00, 0*6, 0x7F,       0,         /* 1 byte sequence */
      0xE0, 0xC0, 1*6, 0x7FF,      0x80,      /* 2 byte sequence */
      0xF0, 0xE0, 2*6, 0xFFFF,     0x800,     /* 3 byte sequence */
      0xF8, 0xF0, 3*6, 0x1FFFFF,   0x10000,   /* 4 byte sequence */
      0xFC, 0xF8, 4*6, 0x3FFFFFF,  0x200000,  /* 5 byte sequence */
      0xFE, 0xFC, 5*6, 0x7FFFFFFF, 0x4000000, /* 6 byte sequence */
      0, /* end of table */
    };
    
    /**
    * 把一个多字节序列转换为一个宽字符
    *
    * @param p 存放计算后的unicode值
    * @param s 需要解析的UTF-8字节序列
    * @param n 字节长度
    * @return 解析的字节长度
    */
    int mbtowc(wchar_t*p, char*s, size_tn)
    {
      long l;  
      int c0, c, nc;  
      Tab *t;
    
      if(s == 0) return0;
      nc = 0;
      //异常校验(可不用关注)
      if(n <= nc) return-1;
      //c0 此处备份一下首字节,后续需要用到前缀码
      c0 = *s & 0xff;
      //l 保存 Unicode 结果
      l = c0;
      /* 遍历tab,从单字节结构->2字节结构->..依次检查找到对应tab */
      for(t=tab; t->cmask; t++) {
        //字节数+1,字节数和tab结构是对应的,也就是当nc=1时 tab结构是单字节,nc=2是tab是两字节
        nc++;
        /* 判断前缀码跟当前的tab是否一致, 如果一致计算最终unicode值并返回*/
        if((c0 & t->cmask) == t->cval) {
          //通过 & Unicode有效值掩码,移除高位前缀码,得到最终unicode值
          l &= t->lmask;
          //异常校验
          if(l < t->lval) return-1;
          //保存结果并反回
          *p = l;
          returnnc;
        }
        //异常校验
        if(n <= nc) return-1;
        //读取下个字节;如果上面判断前缀码不一致,说明需要再读取下个字节
        s++;
        //计算有效位的值,目的是去除UTF-8 编码从第二个字节开始的高两位10
        // 例如 s=10101111、0x80=10000000 计算结果是00101111,这样就去除了高位前缀10
        c = (*s ^ 0x80) & 0xFF;
        //异常校验
        if(c & 0xC0) return-1;
        //重新计算unicode值,根据UTF-8规则c只有低 6 位有效,所以通过移位把c填入到l的低6位
        l = (l<<6) | c;
      }
      //返回异常
      return-1;
    }
    

    ——参考链接

    2024-06-19 08:11:51
    赞同 展开评论
问答地址: