UTF8和GBK编码互转实现解析

 更新时间:2023年07月21日 11:03:16   作者:BEARZPY  
这篇文章主要为大家介绍了UTF8和GBK编码互转实现解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

基本知识

UTF8 本质是 Unicode 标准的一种实现方式,UTF8 编码和 Unicode 字符码是有相互转换的规则的。GBK 码与 Unicode 字符码是没有设计有规律的对应关系的,即没有相互转换的规则。所以想要实现 UTF8 和 GBK 编码互转需要依靠查表法,即 UTF8 转 GBK 编码需要先按规则转换成 Unicode 字符码,再通过查表获取该 Unicode 字符码对应的 GBK 码,同样的 GBK 转 UTF8 编码也需要先查表获取对应的 Unicode 字符码,再按照规则转换成 UTF8 编码。

获取 GBK 和 Unicode 的编码对应表

这里介绍两个编码对应表,分别是 CP936 编码表,和汉字 Unicode 编码表,包含的汉字都是基本汉字,一共 20902 个。除去 ASCII 字符外,这些编码中包括的汉字都是两个字节的长度。 其中 CP936 编码表是按照递增的 GBK 编码值为索引的,对应值是 Unicode 编码,(由于 GBK 的编码并不是连续的,所有索引之间往往有空缺),而汉字 Unicode 编码表是以递增的 Unicode 汉字字符码为索引的,对应值是 GBK 编码(Unicode 编码范围 4E00-9FA5) 。

实现互转

在获取编码表之后,想要实现 GBK 和 Unicode 互转的功能就没有什么难度了,最简单的方法就是定义一个编码数组包含 GBK 和 Unicode 的映射关系,然后对所需要转换的编码进行查表,获取对应编码再拼接成一个数据串就完成了。

采用 CP936 编码表:
需要定义一个 short 型二维数组存放 GBK 和 Unicode 的映射关系(因为 GBK 编码值不是递增的,中间有很多未使用的值),无论是 GBK 转 Unicode 还是 Unicode 转 GBK 使用时最长需要遍历整个数组。

采用汉字 Unicode 编码表:
需要定义一个 short 型一维数组,存放从 4E00-9FA5 直接的汉字字符,Unicode 的编码字符减去 4E00 既是一维数组的索引。在 Unicode 转 GBK 时可以直接计算出对应 GBK 的索引值,直接获取该编码值即可。在 GBK 转 Unicode 的时候最长需要遍历整个数组。

明显可以看出来,使用汉字 Unicode 编码表的时间复杂度和空间复杂度是低于使用 CP936 编码表的,不做优化的话,这里肯定选择汉字 Unicode 编码表。

优化占用空间

缺点:
上面虽然实现了 GBK 和 Unicode 的互相转换,但是在程序里面定一个 20902 长度的 short 数组还是太臃肿了,而且在某些情况嵌入式系统中是不允许定义这么多的。

优化:
这里我们可以把编码表改造成字库文件。在带操作系统的环境下以读取文件的方式来读取字符编码。在嵌入式系统中没有文件系统的环境下,我们可以把字库文件烧入 Flash,以读取 Flash 的方式来读取字符编码。

制作字库文件:
汉字 Unicode 编码表制作字库文件并不复杂,新建一个 .txt 文件(以 ANSI 格式打开),将 Unicode 4E00-9FA5 对应的 GBK 编码依次复制到文件中保存,修改名字为 GBK.bin 就可以了。(这里 GBK.bin 是没有文件头和校验值的,直接按照索引读取就行,需要注意的事这里不能有换行符)

优化查找编码速度

缺点:

使用 GBK.bin 优化了程序占用的空间,但是 GBK 转 Unicode 的时候最长仍需要遍历整个字库文件,而且有一部分常用的字符是在 4E00-9FA5 后段部分的,这就导致了很多情况下查找效率的降低。

优化:

汉字 Unicode 编码表是根据 Unicode 排序的,CP936 编码表是根据 GBK 排序的,我们可以将 CP936 编码表也制作成字库 CP936.bin,在 GBK 转 Unicode 的时候使用字库 CP936.bin,在 Unicode 转 GBK 时使用 GBK.bin,这样互转都是按照编码索引转换成字库索引直接读取对应字库,就省去了遍历的过程。

制作字库文件:

CP936 编码表中的一部分
GBK     Unicode
0x81FD    0x4FA1
0x81FE    0x4FA2
0x8240    0x4FA4
0x8241    0x4FAB

如上所示,GBK 的索引是不连续的,81FE 后面接的是 8240,实际上整个 CP936 中类似于此的断层大概有一百多处,每处缺少的数目是不一样的,这里我们可以通过编写程序将其补全索引,对于的 Unicode 的值设置成 0000,并写入 GBK.bin 文件(这里对于大的断层我们进过滤,并在后面的索引计算中进行特殊处理,以免补出来的 bin 文件过大)。

优化字串转换速度

上面都是单个编码去计算索引,读取文件获取编码返回,在大量的字符串转换的时候会有很多冗余的操作,我们可以进行流程上的优化,把所有需要获取的字符编码先全部转换成索引,然后在去字库中一次将所有需要的内容都读出来统一返回,这样减少了流程上的调用。

UTF8 和 Unicode 的互转

GBK 和 Unicode 的互转已经实现了,剩下的就是 UTF8 和 Unicode 的转换,这部分就有固定的转换规则如下:

UTF8 编码规则:如果只有一个字节则其最高二进制位为 0,如果是多字节,其第一个字节从最高位开始,连续的二进制位值为 1,1 的个数决定了其编码的字节数,其余各字节均以 10 开头。

// Unicode6.1定义范围:0~10 FFFF
// 20 0000 ~ 3FF FFFF 和 400 0000 ~ 7FFF FFFF 属于 UCS-4,UTF8 现在已经弃用了这部分内容
---------------------------------------------------------------------------------
n | Unicode (十六进制)     | UTF - 8 (二进制)
--+-----------------------+------------------------------------------------------
1 | 0000 0000 - 0000 007F | 0xxxxxxx
2 | 0000 0080 - 0000 07FF | 110xxxxx 10xxxxxx
3 | 0000 0800 - 0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
4 | 0001 0000 - 0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
---------------------------------------------------------------------------------
// 以下部分弃用
5 | 0020 0000 - 03FF FFFF | 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
6 | 0400 0000 - 7FFF FFFF | 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
---------------------------------------------------------------------------------

以上就是UTF8和GBK编码互转实现解析的详细内容,更多关于UTF8 GBK编码互转的资料请关注脚本之家其它相关文章!

相关文章

  • 微信小程序 iPhoneX底部安全区域(底部小黑条)适配(一分钟解决)

    微信小程序 iPhoneX底部安全区域(底部小黑条)适配(一分钟解决)

    iPhone X 对于微信小程序的tabbar来说,会被底部小黑条覆盖,需要处理,大概思路是,得到手机型号、分别判断样式。这篇文章主要介绍了微信小程序 iPhoneX底部安全区域(底部小黑条)适配问题,需要的朋友可以参考下
    2019-10-10
  • VSCode设置默认浏览器打开的两种方式

    VSCode设置默认浏览器打开的两种方式

    在使用vscode编辑器的时候,如果我们不设置默认浏览器,那么直接打开的是IE浏览器,在进行页面调试的时候无疑是有点麻烦的,这篇文章主要给大家介绍了关于VSCode设置默认浏览器打开的两种方式,需要的朋友可以参考下
    2023-09-09
  • 声音验证码制作方法

    声音验证码制作方法

    收听验证码已经比较普遍了,使用户看不清楚的情况下可以通过耳朵来收听验证码,但网上搜了很久没看到有具体的制作方法,自己想了想,还是按自己的方法来实现了,呵呵。
    2009-06-06
  • i++循环与i-–循环的执行效率(递增与递减效率)

    i++循环与i-–循环的执行效率(递增与递减效率)

    i++循环与i-–循环的执行效率(递增与递减效率),需要的朋友可以参考下。
    2011-01-01
  • 水晶报表 分页 的问题

    水晶报表 分页 的问题

    在论坛上经常会看到水晶报表分页的问题,这个很好解决。但是自动插入空白行的问题却一直没有很好的答案,经过研究找到一个变通的办法来实现了。
    2009-04-04
  • 解决VS2017不能打开stdio.h等文件的问题

    解决VS2017不能打开stdio.h等文件的问题

    下面小编就为大家带来一篇解决VS2017不能打开stdio.h等文件的问题。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-07-07
  • git分支或指定文件回退到指定版本命令详解

    git分支或指定文件回退到指定版本命令详解

    作为一名后端开发,相信大家一定遇到过这样的情景,代码开发人员过多,并且开发分支过多,导致代码版本管理困难,这样就难免遇到一些代码合并出错,下面这篇文章主要给大家介绍了关于git分支或指定文件回退到指定版本命令的相关资料,需要的朋友可以参考下
    2023-12-12
  • 在 WordPress 的页眉(header)和页脚(footer)添加代码方法

    在 WordPress 的页眉(header)和页脚(footer)添加代码方法

    这篇文章主要介绍了在 WordPress 的页眉(header)和页脚(footer)添加代码方法
    2021-09-09
  • 前端常用的Chrome调试技巧最全汇总

    前端常用的Chrome调试技巧最全汇总

    作为一个前端开发者,我们每时每刻都跟浏览器打交道,在开发的过程中,我们需要不断的在浏览器中查看编写的成果,合理使用浏览器的控制台功能,这篇文章主要给大家介绍了关于前端常用Chrome调试技巧的相关资料,需要的朋友可以参考下
    2024-09-09
  • Git远程仓库配置SSH的实现(以github为例)

    Git远程仓库配置SSH的实现(以github为例)

    本文主要介绍了Git远程仓库配置SSH的实现(以github为例),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-07-07

最新评论