文档章节

如何破译乱码

突然帅了
 突然帅了
发布于 2015/04/25 21:48
字数 3123
阅读 15
收藏 1
点赞 0
评论 0

背景:字符集和编码无疑是IT菜鸟甚至是各种大神的头痛问题。当遇到纷繁复杂的字符集,各种火星文和乱码时,问题的定位往往变得非常困难。本文就将会从原理方面对字符集和编码做个简单的科普介绍,同时也会介绍一些通用的乱码故障定位的方法以方便读者以后能够更从容的定位相关问题。在正式介绍之前,先做个小申明:如果你希望非常精确的理解各个名词的解释,那么可以查阅wikipedia。本文是博主通过自己理解消化后并转化成易懂浅显的表述后的介绍。

什么是字符集
在介绍字符集之前,我们先了解下为什么要有字符集。我们在计算机屏幕上看到的是实体化的文字,而在计算机存储介质中存放的实际是二进制的比特流。那么在这两者之间的转换规则就需要一个统一的标准,否则把我们的U盘插到老板的电脑上,文档就乱码了;小伙伴QQ上传过来的文件,在我们本地打开又乱码了。于是为了实现转换标准,各种字符集标准就出现了。简单的说字符集就规定了某个文字对应的二进制数字存放方式(编码)和某串二进制数值代表了哪个文字(解码)的转换关系。
那么为什么会有那么多字符集标准呢?这个问题实际非常容易回答。问问自己为什么我们的插头拿到英国就不能用了呢?为什么显示器同时有DVI,VGA,HDMI,DP这么多接口呢?很多规范和标准在最初制定时并不会意识到这将会是以后全球普适的准则,或者处于组织本身利益就想从本质上区别于现有标准。于是,就产生了那么多具有相同效果但又不相互兼容的标准了。
说了那么多我们来看一个实际例子,下面就是屌这个字在各种编码下的十六进制和二进制编码结果,怎么样有没有一种很屌的感觉?

什么是字符编码
字符集只是一个规则集合的名字,对应到真实生活中,字符集就是对某种语言的称呼。例如:英语,汉语,日语。对于一个字符集来说要正确编码转码一个字符需要三个关键元素:字库表(character repertoire)、编码字符集(coded character set)、字符编码(character encoding form)。其中字库表是一个相当于所有可读或者可显示字符的数据库,字库表决定了整个字符集能够展现表示的所有字符的范围。编码字符集,即用一个编码值code point来表示一个字符在字库中的位置。字符编码,将编码字符集和实际存储数值之间的转换关系。一般来说都会直接将code point的值作为编码后的值直接存储。例如在ASCII中A在表中排第65位,而编码后A的数值是0100 0001也即十进制的65的二进制转换结果。
看到这里,可能很多读者都会有和我当初一样的疑问:字库表和编码字符集看来是必不可少的,那既然字库表中的每一个字符都有一个自己的序号,直接把序号作为存储内容就好了。为什么还要多此一举通过字符编码把序号转换成另外一种存储格式呢?其实原因也比较容易理解:统一字库表的目的是为了能够涵盖世界上所有的字符,但实际使用过程中会发现真正用的上的字符相对整个字库表来说比例非常低。例如中文地区的程序几乎不会需要日语字符,而一些英语国家甚至简单的ASCII字库表就能满足基本需求。而如果把每个字符都用字库表中的序号来存储的话,每个字符就需要3个字节(这里以Unicode字库为例),这样对于原本用仅占一个字符的ASCII编码的英语地区国家显然是一个额外成本(存储体积是原来的三倍)。算的直接一些,同样一块硬盘,用ASCII可以存1500篇文章,而用3字节Unicode序号存储只能存500篇。于是就出现了UTF-8这样的变长编码。在UTF-8编码中原本只需要一个字节的ASCII字符,仍然只占一个字节。而像中文及日语这样的复杂字符就需要2个到3个字节来存储。
UTF-8和Unicode的关系
看完上面两个概念解释,那么解释UTF-8和Unicode的关系就比较简单了。Unicode就是上文中提到的编码字符集,而UTF-8就是字符编码,即Unicode规则字库的一种实现形式。随着互联网的发展,对同一字库集的要求越来越迫切,Unicode标准也就自然而然的出现。它几乎涵盖了各个国家语言可能出现的符号和文字,并将为他们编号。Unicode的编号从0000开始一直到10FFFF共分为16个Plane,每个Plane中有65536个字符。而UTF-8则只实现了第一个Plane,可见UTF-8虽然是一个当今接受度最广的字符集编码,但是它并没有涵盖整个Unicode的字库,这也造成了它在某些场景下对于特殊字符的处理困难(下文会有提到)。
UTF-8编码简介
为了更好的理解后面的实际应用,我们这里简单的介绍下UTF-8的编码实现方法。即UTF-8的物理存储和Unicode序号的转换关系。
UTF-8编码为变长编码。最小编码单位(code unit)为一个字节。一个字节的前1-3个bit为描述性部分,后面为实际序号部分。
1、如果一个字节的第一位为0,那么代表当前字符为单字节字符,占用一个字节的空间。0之后的所有部分(7个bit)代表在Unicode中的序号。
2、如果一个字节以110开头,那么代表当前字符为双字节字符,占用2个字节的空间。110之后的所有部分代表在Unicode中的序号。且第二个字节以10开头
3、如果一个字节以1110开头,那么代表当前字符为三字节字符,占用3个字节的空间。110之后的所有部分代表在Unicode中的序号。且第二、第三个字节以10开头
4、如果一个字节以10开头,那么代表当前字节为多字节字符的第二个字节。10之后的所有部分代表在Unicode中的序号。
具体每个字节的特征可见下表,其中x代表序号部分,把各个字节中的所有x部分拼接在一起就组成了在Unicode字库中的序号:

细心的读者不难从以上的简单介绍中得出以下规律:

1、3个字节的UTF-8十六进制编码一定是以E开头的
2、2个字节的UTF-8十六进制编码一定是以C或D开头的
3、1个字节的UTF-8十六进制编码一定是以比8小的数字开头的
为什么会出现乱码
先科普下乱码的英文native说法是mojibake。
简单的说乱码的出现是因为:编码和解码时用了不同或者不兼容的字符集。对应到真实生活中,就好比是一个英国人为了表示祝福在纸上写了bless(编码过程)。而一个法国人拿到了这张纸,由于在法语中bless表示受伤的意思,所以认为他想表达的是受伤(解码过程)。这个就是一个现实生活中的乱码情况。在计算机科学中一样,一个用UTF-8编码后的字符,用GBK去解码。由于两个字符集的字库表不一样,同一个汉字在两个字符表的位置也不同,最终就会出现乱码。
我们来看一个例子:假设我们用UTF-8编码存储很屌两个字,会有如下转换:

解码后我们就得到了寰堝睂这么一个错误的结果,更要命的是连字符个数都变了。

如何识别乱码本来想要表达的文字
要从乱码字符中反解出原来的正确文字需要对各个字符集编码规则有较为深刻的掌握。但是原理很简单,这里用最常见的UTF-8被错误用GBK展示时的乱码为例,来说明具体反解和识别过程。
第1步 编码
假设我们在页面上看到寰堝睂这样的乱码,而又得知我们的浏览器当前使用GBK编码。那么第一步我们就能先通过GBK把乱码编码成二进制表达式。当然查表编码效率很低,我们也可以用以下SQL语句直接通过MySQL客户端来做编码工作:
mysql [localhost] {msandbox} > select hex(convert('寰堝睂' using gbk));
+-------------------------------------+
| hex(convert('寰堝睂' using gbk))    |
+-------------------------------------+
| E5BE88E5B18C                        |
+-------------------------------------+
1 row in set (0.01 sec)
第2步 识别
现在我们得到了解码后的二进制字符串E5BE88E5B18C。然后我们将它按字节拆开。

然后套用之前UTF-8编码介绍章节中总结出的规律,就不难发现这6个字节的数据符合UTF-8编码规则。如果整个数据流都符合这个规则的话,我们就能大胆假设乱码之前的编码字符集是UTF-8。
第3步 解码
然后我们就能拿着E5BE88E5B18C用UTF-8解码,查看乱码前的文字了。当然我们可以不查表直接通过SQL获得结果:
mysql [localhost] {msandbox} ((none)) > select convert(0xE5BE88E5B18C using utf8);
+------------------------------------+
| convert(0xE5BE88E5B18C using utf8) |
+------------------------------------+
| 很屌                               |
+------------------------------------+
1 row in set (0.00 sec)
常见问题处理之Emoji
所谓Emoji就是一种在Unicode位于\u1F601-\u1F64F区段的字符。这个显然超过了目前常用的UTF-8字符集的编码范围\u0000-\uFFFF。Emoji表情随着IOS的普及和微信的支持越来越常见。

那么Emoji字符表情会对我们平时的开发运维带来什么影响呢?最常见的问题就在于将他存入MySQL数据库的时候。一般来说MySQL数据库的默认字符集都会配置成UTF-8(三字节),而utf8mb4在5.5以后才被支持,也很少会有DBA主动将系统默认字符集改成utf8mb4。那么问题就来了,当我们把一个需要4字节UTF-8编码才能表示的字符存入数据库的时候就会报错:ERROR 1366: Incorrect string value: '\xF0\x9D\x8C\x86' for column 。如果认真阅读了上面的解释,那么这个报错也就不难看懂了。我们试图将一串Bytes插入到一列中,而这串Bytes的第一个字节是\xF0意味着这是一个四字节的UTF-8编码。但是当MySQL表和列字符集配置为UTF-8的时候是无法存储这样的字符的,所以报了错。
那么遇到这种情况我们如何解决呢?
有两种方式:第一种,升级MySQL到5.6或更高版本,并且将表字符集切换至utf8mb4。第二种方法就是在把内容存入到数据库之前做一次过滤,将Emoji字符替换成一段特殊的文字编码,然后再存入数据库中。之后从数据库获取或者前端展示时再将这段特殊文字编码转换成Emoji显示。第二种方法我们假设用-*-1F601-*-来替代4字节的Emoji。



本文转载自:http://cn.ui.vmall.com/thread-3908150-1-1.html

共有 人打赏支持
突然帅了
粉丝 8
博文 86
码字总数 28698
作品 0
西安
二战时图灵机破译的Enigma密码,现在AI仅需13分钟便可破译

第二次世界大战期间,布莱切利园是英国破译密码的中心。图灵当时也在那里工作。密码破译者的天才工作挽救了许多平民和士兵的生命,据说将战争缩短了两年。 Enigma密码机非常复杂,它最先进的...

技术小能手 ⋅ 2017/12/11 ⋅ 0

云计算服务推动口令破译技术走向新时代

云计算服务推动口令破译技术走向新时代 Jack zhai 问题提出: 口令攻击(就是破译或盗取已知账户的口令进行入侵)是黑客最直接也是最有效的方式,我们熟知的系统管理员账户上最容易被攻击的。 ...

余二五 ⋅ 2017/11/23 ⋅ 0

bitlocker加密软件问题

请问一下bitlocker加密后的磁盘 如果丢失了 数据有没有被破译的风险,大概多大的可能被破译,是暴力破译,还是靠漏洞呀? 同时想请教一下Linux下有没有bitlocker这样的软件,或者有没有开源的类似...

Jack001 ⋅ 2014/07/09 ⋅ 1

计算机科学家利用“数学拼图”加密软件

UCLA计算机科学教授Amit Sahai和一个研究团队联合开发出“数学拼图技术”去 加密软件,这项技术将能防止逆向工程破译代码。他们所研究的技术又名“软件模糊”,其挑战在于加密代码片段但又要...

oschina ⋅ 2013/08/05 ⋅ 5

QQ缓存图片找出QQ号码

@zhengzhx 你好,5F35606056102557CF35554FA181562D.png大神,能否帮我破译一下这个QQ缓存图片的号码?这个人对我很重要!!!!号码是9位数的QQ,开头我记得好像是7,我的电话号码是1508948...

墨随 ⋅ 2015/02/27 ⋅ 23

“九”答不可 | 量子通信如何做到安全保密?

导读 打个电话,会不会被窃听?通过网络传送一份保密文件,途中被他人窃取咋办……现代社会,信息安全面临的问题越来越多。 有没有一种不可破译的保密方式,能让传送的信息绝对安全可靠?量子...

雪花又一年 ⋅ 05/03 ⋅ 0

浅谈密码存储安全

前言 用户信息泄露事件层出不穷,百度或谷歌输入“密码泄露”,搜出来的泄密门更是让人目瞪口呆:从小公司到大公司,从明文存储到普通的哈希加密。作为一个IT从业者,我深刻感受到“得用户者...

等风起 ⋅ 2015/08/13 ⋅ 23

PasswordMaker

用一个口令统辖全部密码! 也许你像大多数人一样,会在许多不同的网站上使用几个相同的密码。你也知道这并不安全,却不得已而为之,为什么?因为牢记每个站点的不同的密码简直难如登天。 Pa...

匿名 ⋅ 2008/09/19 ⋅ 0

go语言中椭圆曲线加密算法的使用

椭圆曲线加密算法,使用golang的实现! 最近在看一些关于比特币的东西,里边有个椭圆曲线加密算法,查了下,感觉很不错! 与经典的RSA,DSA等公钥密码体制相比,椭圆密码体制有以下优点: 1.安全性...

IrvinYoung ⋅ 2016/10/09 ⋅ 0

如何提高Android设备安全性?5个窍门赶紧get吧!

目前在市场上,Android设备的数量是非常惊人的。2011年第一季度,Android在全球的市场份额首次超过塞班系统,跃居全球第一。 2013年的第四季度,Android平台手机的全球市场份额已经达到78.1%...

Miss_Hello_World ⋅ 2015/08/20 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

个人博客的运营模式能否学习TMALL天猫质量为上?

心情随笔|个人博客的运营模式能否学习TMALL天猫质量为上? 中国的互联网已经发展了很多年了,记得在十年前,个人博客十分流行,大量的人都在写博客,而且质量还不错,很多高质量的文章都是在...

原创小博客 ⋅ 49分钟前 ⋅ 0

JavaScript零基础入门——(十一)JavaScript的DOM操作

JavaScript零基础入门——(十一)JavaScript的DOM操作 大家好,欢迎回到我们的JavaScript零基础入门。最近有些同学问我说,我讲的的比书上的精简不少。其实呢,我主要讲的是我在开发中经常会...

JandenMa ⋅ 今天 ⋅ 0

volatile和synchronized的区别

volatile和synchronized的区别 在讲这个之前需要先了解下JMM(Java memory Model :java内存模型):并发过程中如何处理可见性、原子性、有序性的问题--建立JMM模型 详情请看:https://baike.b...

MarinJ_Shao ⋅ 今天 ⋅ 0

深入分析Kubernetes Critical Pod(一)

Author: xidianwangtao@gmail.com 摘要:大家在部署Kubernetes集群AddOn组件的时候,经常会看到Annotation scheduler.alpha.kubernetes.io/critical-pod"="",以表示这是一个关键服务,那你知...

WaltonWang ⋅ 今天 ⋅ 0

原子性 - synchronized关键词

原子性概念 原子性提供了程序的互斥操作,同一时刻只能有一个线程能对某块代码进行操作。 原子性的实现方式 在jdk中,原子性的实现方式主要分为: synchronized:关键词,它依赖于JVM,保证了同...

dotleo ⋅ 今天 ⋅ 0

【2018.06.22学习笔记】【linux高级知识 14.4-15.3】

14.4 exportfs命令 14.5 NFS客户端问题 15.1 FTP介绍 15.2/15.3 使用vsftpd搭建ftp

lgsxp ⋅ 今天 ⋅ 0

JeeSite 4.0 功能权限管理基础(Shiro)

Shiro是Apache的一个开源框架,是一个权限管理的框架,实现用户认证、用户授权等。 只要有用户参与一般都要有权限管理,权限管理实现对用户访问系统的控制,按照安全规则或者安全策略控制用户...

ThinkGem ⋅ 昨天 ⋅ 0

python f-string 字符串格式化

主要内容 从Python 3.6开始,f-string是格式化字符串的一种很好的新方法。与其他格式化方式相比,它们不仅更易读,更简洁,不易出错,而且速度更快! 在本文的最后,您将了解如何以及为什么今...

阿豪boy ⋅ 昨天 ⋅ 0

Python实现自动登录站点

如果我们想要实现自动登录,那么我们就需要能够驱动浏览器(比如谷歌浏览器)来实现操作,ChromeDriver 刚好能够帮助我们这一点(非谷歌浏览器的驱动有所不同)。 一、确认软件版本 首先我们...

blackfoxya ⋅ 昨天 ⋅ 0

线性回归原理和实现基本认识

一:介绍 定义:线性回归在假设特证满足线性关系,根据给定的训练数据训练一个模型,并用此模型进行预测。为了了解这个定义,我们先举个简单的例子;我们假设一个线性方程 Y=2x+1, x变量为商...

wangxuwei ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部