当前位置: 首页 > article >正文

史上最简单易懂的 简析utf-8编码

对于程序员来说utf-8编码那真是很常见的了,但试问有多少人知道utf-8内在的原理?下面我尽量使用最短的时间让你了解utf-8。这里不讨论编码历史的发展,那对于现在的你可能毫无意义。假定你对二进制有所了解,并且理解无符号和有符号二进制。

简单的说utf-8就是一张数字和符号的映射表。那么解码的过程就是把二进制串解析成数字,然后从这张表中找到对应的字符。反之就是编码的过程。这个数字是无符号二进制。

那么问题随之就来了,怎么得到这个数字?要回答这个问题就得了解utf-8的结构了,utf-8编码可能占用1个字节也可能占用多个字节,但就目前规定最多占4个字节,所以说UTF-8编码为变长编码(科普:java中汉字的utf-8占用3个字节)。utf-8结构如下:

占用字节数第1个字节第2个字节第3个字节第4个字节16进制数字范围
10xxxxxxx   0000到007F
2110xxxxx10xxxxxx  0080 到07FF
31110xxxx10xxxxxx10xxxxxx 0800到FFFF
411110xxx10xxxxxx10xxxxxx10xxxxxx10000到1FFFFF

从这张结构图中我们就可以总结出找到数字的方法。

  • 如果一个字节的第一位为0,那么当前字符占用1个字节的空间。
  • 如果一个字节的第一位为110,那么当前字符占用2个字节的空间。
  • 如果一个字节的第一位为1110,那么当前字符占用3个字节的空间。
  • 如果一个字节的第一位为11110,那么当前字符占用4个字节的空间。

也就是说根据首字节就可以判断出该字符占用的二进制串的长度。自然就可以得出一个无符号的数字,然后用这个数字在utf-8的编码表中找到对应的字符就可以了。到现在你已经完全掌握了utf-8编码。

下面锁一个小例子,把下面的utf-8编码的二进制串解码:

111001101000100010010001111001111000100010110001111001001011110110100000

当然我们可以按照8位为单元把二进制串转成字节数组,然后按照utf-8编码传递给String对象就可以得到想要的答案,这里为了理解utf-8编码,模拟解码过程。代码如下:

package utf8;public class TestUtf8 {public static void main(String[] args) throws Exception {String binaryString = "111001101000100010010001111001111000100010110001111001001011110110100000";while(!binaryString.equals("")){binaryString = decode(binaryString);}}/*** 解码* @param binaryString* @return* @throws Exception*/private static String decode(String binaryString)throws Exception{//找到当前二进制串String curBinaryString = findCurBinary(binaryString);//把当前二进制串装为字符,也就是找数字对应的字符binaryToChar(curBinaryString);//范围剩余二进制串return findLeftBinary(binaryString);}/*** 找到当前二进制串* @param binaryString* @return*/private static String findCurBinary(String binaryString){if(binaryString.startsWith("0")){//1个字节return binaryString.substring(0,8);}else if(binaryString.startsWith("110")){//2两个字节return binaryString.substring(0,16);}else if(binaryString.startsWith("1110")){//3个字节return binaryString.substring(0,24);}else if(binaryString.startsWith("11110")){//4个字节return binaryString.substring(0,32);}return "";}/*** 范围剩余二进制串* @param binaryString* @return*/private static String findLeftBinary(String binaryString){if(binaryString.startsWith("0")){//1个字节return binaryString.substring(8);}else if(binaryString.startsWith("110")){//2两个字节return binaryString.substring(16);}else if(binaryString.startsWith("1110")){//3个字节return binaryString.substring(24);}else if(binaryString.startsWith("11110")){//4个字节return binaryString.substring(32);}return "";}/*** 模拟查找数字对应字符* @return*/private static void binaryToChar(String binaryString)throws Exception{byte [] bytes = new byte[binaryString.length()/8];for(int i=0;i<bytes.length;i++){String substring = binaryString.substring(i * 8, i * 8 + 8);bytes[i] = Integer.valueOf(substring,2).byteValue();}String result = new String(bytes, "utf-8");System.out.print(result);}}

当然你可以使用下面的方法:

package utf8;public class TestUtf8 {public static void main(String[] args) throws Exception {String binaryString = "111001101000100010010001111001111000100010110001111001001011110110100000";binaryToChar(binaryString);}/*** 模拟查找数字对应字符* @return*/private static void binaryToChar(String binaryString)throws Exception{byte [] bytes = new byte[binaryString.length()/8];for(int i=0;i<bytes.length;i++){String substring = binaryString.substring(i * 8, i * 8 + 8);bytes[i] = Integer.valueOf(substring,2).byteValue();}String result = new String(bytes, "utf-8");System.out.print(result);}}

 

想知道结果运行程序即可。

当然知道了utf-8编码的原理,你还可以解决一些实际问题,比如你的mysql数据库编码是utf-8的,那么mysql默认的utf-8编码最多支持3个字节。这就会导致存储一些占用4个字节的内容会导致错误。这个时候你可以利用你掌握的原理,把首字节开头为11110的二进制串过滤掉,然后再进行存储。也可以利用二进制串表示数字大于FFFF的就过滤掉。当然最简单的方法就是把数据库编码换成utf8mb4,也就是支持4个字节的utf-8编码。

 

http://www.lryc.cn/news/2416751.html

相关文章:

  • C语言实战-贪吃蛇
  • 沟通CTBS物流行业远程接入解决方案
  • STM32CubeMX 下载安装使用(一)
  • H3C交换机配置DHCP中继
  • 编译hyperscan
  • CydiaSubstrate的简单使用
  • 探索MS17-010漏洞利用工具:All-In-One全方位解析
  • mysql用decimal_MySQL数据类型DECIMAL用法详解
  • MySQL - 存储过程 [Stored Procedure] - 学习/实践
  • INA3221和 ESP8266 6通道电流表
  • HTML自动暂停按钮,css 播放暂停按钮实现_html/css_WEB-ITnose
  • Linux命令及详解
  • c语言学习网站大全
  • 部署weblogic
  • 设计模式、设计模式的分类、作用、介绍
  • pushpop指令的操作数必须是字操作数_欧姆龙PLC(CPM1A)功能指令
  • VC++程序由Visual Studio 2003升级到Visual Studio 2005手记
  • (八)SQL SELECT INTO 语句和 INSERT INTO SELECT 语句
  • VS2010序列号(激活码)
  • Java的日期类说明Calendar、Data、日期转化格式化以及注意事项
  • 移动开发最新腾讯一面:请你分别谈谈SharedPreferences 和MMKV,2024年最新今日头条测试面试题
  • GNS3-1.3.10环境部署(新手必备,通俗易懂)
  • 虚拟语气用法总结及真题解析
  • 一键彻底清理!解密如何清理电脑C盘垃圾的绝佳方法
  • linux系统无线驱动在哪下载,在Linux系统中BCM4356无线网卡驱动问题的解决
  • java的递归详细讲解
  • 非常值得收藏的15个 Google 高级搜索技巧
  • Java ClassLoader getResources()方法与示例
  • 计算机毕设ssmSSM农村电商网站3252s(开题+源码)
  • 【个人学习笔记】统一网关gateway