这个例程是在书上看到的,感觉很有意思。

简单介绍一下utf-8编码,utf-8编码是一种变长的编码方式,长度为1-4字节。

当码长为1字节的时候,兼容ascii编码,格式为0xxxxxxx (x处表示有效位)

当码长为2字节的时候,格式为110xxxxx 10xxxxxx

高字节的110表示码长为2字节,低字节的10为低字节标志位,下同

当码长为3字节的时候,格式为1110xxxx 10xxxxxx 10xxxxxx

当码长为4字节的时候,格式为11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

我们先来看一下头文件 unicodeUtf8.h

/*这段代码是utf8编码解码器头文件,在书p66*/
#ifndef _INCLUDE_UTF8_H
#define _INCLUDE_UTF8_H
#include <stdint.h>
uint32_t getByteNumOfEncodeUtf8(int value);
uint32_t getByteNumOfDecodeUtf8(uint8_t byte);
uint8_t encodeUtf8(uint8_t* buf, int value);
int decodeUtf8(const uint8_t* bytePtr, uint32_t length);
#endif

getByteNumOfEncodeUtf8 计算编码后的字节长度

getByteNumOfDecodeUtf8 计算解码后的字节长度

encodeUtf8 编码

decodeUtf8 解码

具体的实现代码

/*这段代码是utf8编码解码器具体实现代码,在书p61*/
#include "unicodeUtf8.h"
#include "common.h"/*详细的ascii码编码规则见书P60*///返回value按照utf8编码后的字节数
uint32_t getByteNumOfEncodeUtf8(int value){ASSERT(value>0, "can't encode negative value!\n");  //只能对正数编码//单个ASCII码字符需要1个字节if(value <= 0x7f){return 1;}//此范围需要2字节if(value <= 0x7ff){return 2;}//此范围需要3字节if(value <= 0xffff){return 3;}//此范围需要4字节if(value <= 0x10ffff){return 4;}//超过范围返回0return 0;
}//把value编码为utf8后写入缓冲区buf,返回写入的字节数
//详细的解释在书p65
uint8_t encodeUtf8(uint8_t* buf, int value){ASSERT(value>0, "can't encode negative value!\n");  //只能对正数编码//按照大端字节序写入缓冲区(低地址对应高数据位)if(value <= 0x7f){*buf = value & 0x7f;   //讲value存入内存中return 1;}   else if(value <= 0x7ff){//这种情况下utf8格式为110xxxxx 10xxxxxx//先在低地址处写入高字节110xxxxx//11000000 | ((value & 0111 1100 0000)>>6)*buf++ = 0xc0 | ((value & 0x7c0)>>6);//再在高地址处写入低字节10xxxxxx//1000 0000 | (value & 0011 1111)*buf = 0x80 | (value & 0x3f);return 2;}else if(value <= 0xffff){//这种情况下utf8格式为1110xxxx 10xxxxxx 10xxxxxx//先在低地址写入高字节1110xxxx*buf++ = 0xe0 | ((value & 0xf0000)>>12);//然后在中地址写入中字节*buf++ = 0x80 | ((value & 0xfc0)>>6);//最后在高地址写入低字节*buf = 0x80 | (value & 0x3f);return 3;}else if(value <= 0x10ffff){//在这种情况下utf8格式为11110xxx 10xxxxxx 10xxxxxx 10xxxxxx//先在低地址写入高字节11110xxx*buf++ = 0xf0 | ((value & 0x1c0000)>>18);//再在第二段地址写入第二段字节10xxxxxx*buf++ = 0x80 | ((value & 0x3f00)>>12);//然后在第三段地址写入第三段字节10xxxxxx*buf++ = 0x80 | ((value & 0xfc0)>>6);//最后在高地址写入低字节10xxxxxx*buf = 0x80 | (value & 0x3f);return 4;}NOT_REACHED();  //如果程序运行到这里就是错了return 0;
}//返回解码utf8的字节数
uint32_t getByteNumOfDecodeUtf8(uint8_t byte){//byte应该是utf8的最高1字节,如果指向了utf8编码后面低字节部分则返回0if((byte & 0xc0)==0x80) return 0;  //1000 0000if((byte & 0xf8)==0xf0) return 4;  //1111 0000if((byte & 0xf0)==0xf0) return 3;  //1110 0000if((byte & 0xe0)==0xc0) return 2;  //1100 0000return 1;          //ASCII码
}//解码以bytePtr为起始地址的utf8序列,其最大长度为length,若不是utf8序列就返回-1
int decodeUtf8(const uint8_t* bytePtr, uint32_t length){//若是1字节的ascii码: 0xxxxxxxif(*bytePtr <= 0x7f) return *bytePtr;int value;uint32_t remainingBytes;//先读取高1字节//根据高1字节的高n位判断相应字节数的utf8编码if((*bytePtr & 0xe0)==0xc0){//若是2字节的utf8value = *bytePtr & 0x1f; //记录后面的5位有效位remainingBytes = 1;}  else if((*bytePtr & 0xf0)==0xe0){//若是3字节的utf8value = *bytePtr & 0x0f; //记录后面的4位有效位remainingBytes = 2;}else if((*bytePtr & 0xf8)==0xf0){//若是4字节的utf8value = *bytePtr & 0x07;remainingBytes = 3;}else {return -1;} //非法编码//如果utf8被斩断了就不再读下去了if(remainingBytes > length - 1){return -1;}//再读取低字节中的数据while(remainingBytes > 0){bytePtr++;remainingBytes--;//高两位必须是10if((*bytePtr & 0xc0) != 0x80){return -1;}//从次高字节往低字节读value = value << 6 | (*bytePtr & 0x3f); //value左移6为写入6位有效位}return value;   //返回解码得到的value值
}

下面我就简单介绍一下编码和解码的算法

编码

我们以3字节码长为例, 当我们的value是12-16位二进制数的时候就应该编码成3字节

我们采用大端字节序,也就是数据位的高位存放在内存的低地址处,数据位的地位存放在内存的高地址处

所以我们先存高1字节,高1字节的格式为 1110 xxxx ,有4位有效为,这4位有效位是value的高4位

我们把value当16位二进制数来看

首先用 value & 0xf000 (也就是 1111 0000 0000 0000) 然后右移12位来得到高4位

之后用0xe0(即1110 0000)或 来得到头标志1110

编码第二个字节的时候也是同样的道理 我们要将value 的第7-12为写入编码中

首先 value & 0xfc0 (即1111 1100 0000)来获得7-12位 然后右移6位

之后用0x80 (即1000 0000)来得到次字节表示10

最后使用第6位写入编码

先用value & 0x3f ( 即0011 1111 )来获得低6位

然后使用0x80获得头10

解码

解码的时候我们先获取高1字节来判断后面有几个字节,然后再继续解码

如果只有一个字节那么它就是ascii码,直接返回即可

如果是两个字节,也就是说 (*bytePtr & 0xe0) == 0xc0 的时候我们还要继续往后读一个字节,此时最高位上有5位有效位

value = *bytePtr & 0x1f 得到5位有效位

三字节和四字节同理,并且有效位逐个减小一位

之说以用0xe0与是因为头标志为110,之后才是有效的数据位 

 在我们读后面的字节的时候用 (*bytePtr & 0xc0) == 0x80 来判断它是正确编码

然后读取第6位最为有效位写入value中

先 *bytePtr & 0x3f 来获取低6位, 然后value 左移6位再或上得到的低6为即可

参考书籍 《基于c语言自制编程语言》作者 郑钢

c语言实现utf-8编码解码器相关推荐

  1. HTML CSS杂记

    之html (超文本标记语言)css (层叠样式表)杂记 ----------------------------------------------------------------------- ...

  2. Native Rss Reader 的资料

    转:http://hi.baidu.com/mikyliang/blog/item/11d420d3135832013af3cf19.html RSS文档的构成 2007-05-04 14:58 RS ...

  3. c语言输出字符的utf码,C语言里如何把GBK码转换为UTF8?

    C语言里如何把GBK码转换为UTF8? (2013-03-04 19:41:31) 标签: it 一.利用iconv函数族进行编码转换 在LINUX上进行编码转换时,既可以利用iconv函数族编程实现 ...

  4. Java MorseCoder - Java 语言实现的摩尔斯电码编码解码器

    最近在看<编码-隐匿在计算机软件背后的语言>这本书,看到了一张译码表很有意思: 不免让我会想起本科在学编码的那段轻松岁月,于是就去查了如何用Java代码实现这个摩尔的编码和译码过程,代码如 ...

  5. c语言 utf 8转字符串,如何将UTF-8字节[]转换为字符串?

    我有一个byte[]数组,它是从一个我所知道的包含UTF-8的文件中加载的. 在一些调试代码中,我需要将其转换为字符串. 是否有一个班轮可以做到这一点? 在幕后 ,它应该只是一个分配和一个内存复制 , ...

  6. python语言type board_菜鸟学Python,双手奉上老司机给上路新手总结的Python实战问题……...

    针对Python这一话题每天后台都会有不少小伙伴提出问题,下面我就将这些问题进行汇整,产出"Python实战问题篇",我认为这些问题非常具有代表性,希望可以帮到大家. 第一类问题: ...

  7. Swift教程Swift语言快速入门(内部资料)

    Swift语言快速入门(内部资料) 试读下载地址:http://pan.baidu.com/s/1eQCGRHw 前言Swift教程Swift语言快速入门(内部资料)Swift教程Swift语言快速入 ...

  8. python语言中文社区-python中用中文

    广告关闭 2017年12月,云+社区对外发布,从最开始的技术博客到现在拥有多个社区产品.未来,我们一起乘风破浪,创造无限可能. 花下猫语:在 python 中是否可以实现中文数字的四则运算呢? 答案是 ...

  9. python语言中文社区-python解决中文

    广告关闭 腾讯云双11爆品提前享,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高满返5000元! python 添加中文注释时出现运行失败. 需要在顶部设置编码. # coding ...

最新文章

  1. Spring单实例、多线程安全、事务解析
  2. 在Docker里使用(支持镜像继承的)supervisor管理进程(转)
  3. oracle主目录自动检测,ORACLE ADDM数据库自动诊断测试
  4. 关于Android的EditText焦点问题
  5. Python教程:collections的deque()方法
  6. kodexplorer开源网盘php程序配置解析
  7. BZOJ4545: DQS的trie 广义后缀自动机_LCT
  8. 微信小程序之二维仿射变换
  9. python机器学习案例系列教程——逻辑分类/逻辑回归LR/一般线性回归(softmax回归)
  10. spring+hibernate 下载
  11. SpringMVC的乱码问题解决
  12. Excel转PDF方法
  13. 李子奈《计量经济学》第四版笔记和课后答案
  14. 人脸识别门禁系统需求分析文档
  15. java代理模式租房案例
  16. 动态域名解析ipv6 群辉dnspod_群晖设置ipv6动态域名
  17. 教师资格综合素质知识要点记录
  18. 【2021全国高校计算机能力挑战赛Python题目】17.学科竞赛 现有六门功课(语文、数学、物理、化学、政治、历史)的成绩,现在需要从中选拔优秀同学参加如下学科竞赛
  19. python pyecharts 画图 饼图柱状图
  20. 发现一个叫阿尔法城的小站(以后此贴为我记录日常常用网址的帖子了)

热门文章

  1. Cutting a Rod
  2. php 工资条系统下载,发工资条软件
  3. 使用Linux版印象笔记nixnote2
  4. SCOI2014 方伯伯的玉米田 题解
  5. 安卓模拟器刷小米系统_米柚模拟器下载_米柚手游模拟器(在电脑上玩遍小米所有手游) 2.1.9.9 官方版_极速下载站...
  6. PS生成动态的二维码
  7. 网易视频云:流媒体服务器原理和架构解析
  8. 腾讯企鹅辅导 H5 性能极致优化
  9. SpringBoot--多线程07
  10. OC循环渐进:文件管理--计算文件大小的五种方式