前言
最近几天在分析一个字符乱码问题,想知道对方(恶意用户 或者说是黑客)到底想做什么。最后发现对方使用了Unicode字符集进行编码,而我们日志收集端使用的是utf-8编码解码,这就导致了乱码。
不知道大家注意到没上面这段文字中出现了Unicode“字符集”和utf-8“编码”,可能很多朋友都什么是字符集、什么是编码有些分不清。今天就来详细的聊下。
我们都知道电脑只能识别二进制数0和1,我们在显示器上看到的所有符号都可以由多个0和1进行表示。每个二进制位叫做bit,8个bit称为1个字节。每个符号(字符)可以由1个或多个字节表示,换句话说字节是表示符号的最小单位。但二进制不方便人类阅读和查看,一般还会引入十进制和十六进制。
前面提到的“符号”可以简单理解为“电脑”里的一个图标,可以是任意的文字、标点符号、或者声音等等,比如“A”、“中”、“国”。这里的每个“符号”对应了前面提到二进制表示的数字,这里我们暂且称为“符号码”, “电脑”中的每个“符号”都对应了一个“符号码”(一一对应)。无论是硬盘存储还是网络传输数据时,都是用的“符号码”,只是在最终显示的时候“电脑”会根据这个“符号码”查找到对应的“符号”用于展示即可。
那什么是字符集呢,简单的理解就是:字符集=“符号”+“符号码”。我们在安装linux系统时,通常会安装一些字符集,此时就会把对应字符集里定义的“符号”、以及“符号码”对应的码表安装到电脑中。每个字符集又有自己的编码规则,下面分别来看下字符集以及其对应的编码。
字符集
世界各国为了自己国家语言符号的需要,定义了很多字符集。这里只列出常见的几种:ASCII
、ISO8859-1、GB2312、GBK、Unicode(注意这些才是所谓的字符集)。
ASCII
美国人在发明计算机时,只考虑了本国语言,他们在定义“符号”时,只考虑了英语:字母、数字、标点符号等;一共只定义了128个“符号”,对应的“符号码”是从0到127(当然是二进制的)。这就是ASCII码,全称是American Standard Code for Information Interchange,从这个全称上也可以看出只是包含了美国人语言习惯的字符(英语)。
前面提到过表示一个字符(文中提到的字符和“符号”是一个意思)的最小单位是“字节”, ASCII只定义了128个“符号”, 1个字节的低7位就足够了(2的7次方),第一位补0即可。可以看出ASCII是单字节表示。
ISO-8859-1
欧洲一些国家除了使用ASCII中定义的符号外,还有有自己的语言符号。ASCII中不是还有1位没用么,于是他们把这位也利用起来,一共可以表示256个字符(2的8次方)。
ISO-8859-1完全兼容ASCII(反过来却不行,第一个bit位会丢失),也是单字节表示。
GB2312
中文的符号比较特殊,既没有在ASCII中定义 也没有在ISO-8859-1中定义,也就是说刚开始的电脑中是无法显示中文的。由于汉字比较特殊,每个汉字都是一个单独的符号,汉字的个数又多,所以1个字节肯定是不够用的。
GB2312是中国人自己定义的中文字符集,采用两个字节表示。它收录了汉字以及拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母。其中收录汉字6763个,其他文字符号682个。
GBK是对GB2312的扩展,可以表示21003个汉字。换句话说GBK完全兼容GB2312(反之则不行)。
Unicode
每个国家都去定义自己的字符集显然不是一种通用的做法,而且也不便于世界各国的信息交流。假如:中国的电脑上只安装了GB2312字符集,就无法显示用泰语写的文案。有个叫ISO的组织创建了一个全新的字符集Unicode,这个字符中定了世界上所有语言中的符号。另外,unicode字符集的编号兼容了ASCII字符集的编号和ISO 8859-1字符集的编号。
Unicode 目前规划的总空间是17个平面(平面0至16),每个平面有 65536 个码点。
第0个平面的取值范围:0 0000-0 FFFF
第1个平面的取值范围:1 0000-1 FFFF
…
第16个平面的取值范围:F 0000-F FFFF
可以看到Unicode编码需要20个bit位来进行存储。一般而已对应第0个平面 只需要2个字节进行存储;其他平台需要4个字节。在后面的Unicode具体编码规则中 ,又分为多种情况。
编码
编码,或者说字符集的编码 一般的全称为xxx字符集的编码。简单的理解编码就是使用多少个字节以什么样的格式来存储码值。
首先来看最简单的ASCII,没有特殊的编码规则,使用一个字节的低7位存储即可,首位补0。
ISO-8859-1,也没有特殊的编码规则,使用一个字节的全部8为进行存储,不过多的进行解读。
GB2312的编码规则,稍微复杂些。由于GB2312没有定义ASCII中的字符,在遇到英文符号时还是采用单字节的ASCII码;如果是中文字符时,采用双字节进行存储。GB2312中有分区的概念,一共94个区(01-94),每个区定义了94个位置(01-94);分区和分区中的位置都用一个字节表示,此时如果不处理的话,每个字节都跟ASCII码重叠了。GB2312的编码规则是把分区号和位置值都加160,原来的取值范围是0-94,现在变为160-254(一个字节不能超过256,这也是为什么要加160的原因)。
简单的理解GB2312的编码规则:非ASCII字符 使用两个字节进行存储,每个字节的取值范围是160-254;如果某个字节的数值小于128,说明是ASCII字符,这个字符直接使用ASCII进行解析。
GBK字符集的编码规则大致与GB2312类似,只是进行了扩展。
最后重点说下Unicode字符集的编码规则,因为只有这个字符集才能做到全球通用。Unicode字符集的编码方式有多种:UTF-8、UTF-16、UTF-32。注意utf是编码,Unicode是字符集 这就是文章的主题:编码和字符集的区别。只是ASCII、ISO-8859-1、GB2312这些字符集的编码规则只有一种,所以有时候既可以说是字符集 又有人说是编码;但Unicode字符集 有多种编码规则,为什么要设置多个编码规则呢?
UTF-16
首先来看UTF的全称:Unicode Transformation Format 其实就是“Unicode字符集的转换格式”。
相信很多人都看到过java中的char使用的Unicode是两个字节,但不要错误的认为Unicode
只采用了两个字节。Unicode 目前规划的总空间是17个平面(平面0至16),每个平面有 65536 个码点,我们常说的两个字节,只是最常用的平面0中定义的字符(又称BMP Basic Multilingual Plane),这时UTF-16编码规则只需要两个字节存储。
另外16个平面 即平面1到16 ,UTF-16编码规则是采用的4个字节进行存储,一共32个bit位。具体格式如下:`110110pp ppxxxxxx 110111xx xxxxxxxx`,其中pp pp这4个字节用于表示16个平面(2的4次方);另外16个x用于表示每个平面中的位置(2的16次方 即65536个位置)。
简单理解UTF-16编码规则:Unicode的第0个平面中的字符用2个字节存储,其他16个平面都是使用的4个字节存储。地球人常用的字符都在第0个平面里面,这个平面只需要2个字节,也比较节省空间。
但有些情况下采用两个字节存储也很浪费空间,比如前面提到的ASCII中的字符,原本只需要1个字节的,现在都需要两个字节(高位字节每个bit都为0)。在存储英文相关字符时,存储空间翻倍,这就产生了UTF-8编码。
UTF-8
UTF-8采用变长技术实现对Unicode字符集的编码,可以采用1-6个字节用来表示Unicode字符集。UTF-8编码规则:如果只有一个字节则其最高二进制位为0;如果是多字节,其第一个字节从最高位开始,连续的二进制位值为1的个数决定了其编码的字节数,其余各字节均以10开头。UTF-8转换表表示如下:
Unicode |
bit数 |
UTF-8 |
字节数 |
备注 |
0000 ~ 007F |
0~7 |
0XXX XXXX |
1 |
|
0080 ~ 07FF |
8~11 |
110X XXXX 10XX XXXX |
2 |
|
0800 ~ FFFF |
12~16 |
1110XXXX 10XX XXXX 10XX XXXX |
3 |
第0个平面中的字符,也称BMP |
1 0000 ~ 1F FFFF |
17~21 |
1111 0XXX 10XX XXXX 10XX XXXX 10XX XXXX |
4 |
其他16个平面中的字符(Unicode定义了20个bit位,这里有21个可以用位,已可以完全覆盖Unicode字符集) |
20 0000 ~ 3FF FFFF |
22~26 |
1111 10XX 10XX XXXX 10XX XXXX 10XX XXXX 10XX XXXX |
5 |
已超出Unicode的范围 |
400 0000 ~ 7FFF FFFF |
27~31 |
1111 110X 10XX XXXX 10XX XXXX 10XX XXXX 10XX XXXX 10XX XXXX |
6 |
从这个图可以看出在UTF-8中,最多使用4个字节就可以覆盖所有的Unicode字符集。另外由于UTF-8使用了变长技术,在大多数情况下比UTF-16更节省空间。
UTF-32
UTF-32编码是一种暴力方式,直接使用4个字节存储Unicode字符集,Unicode字符集的最大值是10FFFF。也就是说使用4个字节来存储Unicode字符集,表示范围如下(16进制):
00 00 00 00 00 ~ 00 10 FF FF。
可以看到至少有1个高位字节全部为0,这是最浪费空间的一种编码方式。也就是最简单的Unicode字符集编码方式。
最后再说下UTF-8、16、32后面这个数字,其含义为最少使用多少个bit位,UTF-8表示最少使用8bit位 即一个字节;UTF-16最少使用16个bit位,2个字节;UTF-32固定使用32个bit位。
总结
最后简单总结下,字符集和编码是有区别的,常见的字符集有ASCII、ISO8859-1、GB2312、GBK、Unicode。ASCII、ISO8859-1、GB2312、GBK这些字符集只有一种编码规则,所以有时候即被称为字符集又被称为编码;Unicode字符集有三种常见的编码:utf-8、utf-16、utf-32。
我们经常遇到的乱码问题,本质就上就是在字符转换成字节流(二进制的字符集编码)是采用了一种编码方式,字节流转换成字符时又使用了另一种编码方式(解码),最终出现乱码。当然不是说所有使用不同的编码进行编解码都会出现乱码,兼容的情况就不会出现乱码:比如用IOS-8859-1解ASCII,用GBK解GB2312,用utf-8解ASCII都不会出现乱码。
字符集中定义的“字符码”值(code point),与编码后的码值 有可能是不相同的。ASCII和IOS-8859-1是相同的,而GB2312和Unicode字符集定义的code point值与编码后的值是不同的。它们的关系如下:
另外字符集和编码也是密码学的基础,基本都是在二进制的编码上进行一些位运算,当然这个计算过程是个复杂是很复杂的。
如果还要更深入的了解字符集和编码想的内容可以参考这一系列文章:https://zhuanlan.zhihu.com/paogenjiudi
相关推荐
这种编码方式的优点在于它保留了ASCII码的特性,即对于ASCII码内的字符,UTF-8编码与ASCII码完全一致,这大大简化了编码和解码的过程。 #### 三、Java中的字符集和编码 在Java中,字符是以16位Unicode编码表示的,...
字符集和字符编码 字符集是指计算机系统支持的所有抽象字符的集合,包括文字、符号、图形符号、数字等。字符编码是将字符转换为二进制数据的过程,反之,解码是将存储在计算机中的二进制数据解析显示出来。 1. ...
在信息技术领域,理解和掌握字符集与字符编码至关重要,因为它们直接影响到数据的存储、传输和显示。以下是对这些概念的详细介绍: 1. **字符集(Character Set)** 字符集是一个集合,包含了所有可能的字符,比如...
字符集和字符编码是计算机处理文本的基础,它们决定了如何将人类使用的文字和符号转换成计算机可以理解的形式。本文档主要介绍了几种常见的字符集和字符编码,包括ASCII、DBCS、GB2312、GBK、GB18030、BIG5以及UCS和...
字符编码和字符集是计算机处理文字和符号的基础。字符集是指一组特定的字符集合,它包含文字、符号、数字等元素。例如,英文字符集包含了所有的英文字母和符号,而汉字字符集则包含了所有汉字。字符集可以是某个语言...
### Java字符集编码乱码详解 #### 一、编码与乱码基础知识 在计算机科学领域,字符集(Character Set)是指一系列符号和电子通信代码的标准集合。每种字符集都有其特定的应用场景和优势。例如,ASCII(American ...
在嵌入式系统中,由于资源有限,往往需要对字符集和编码进行精简处理。GB18030因其广泛的字符覆盖范围,尤其适用于需要处理复杂文本环境的嵌入式设备,如智能电视、移动设备等。然而,由于其四字节编码的特性,相...
字符集和字符编码是计算机处理文字的基础,它们决定了如何在二进制的世界中表示和传输人类语言。本文将深入探讨这两个概念,以及相关的知识点。 首先,我们要理解什么是字符集。字符集,顾名思义,就是一个集合,...
字符集和编码 字符集是计算机中用于表示文字和符号的集合,一个字符集可以包含多种语言的字符,而编码是将字符集中的字符转换为计算机可以识别的数字代码的过程。在本文中,我们将讨论几种常见的字符集和编码方式。...
### 维吾尔文字符集Unicode编码表 #### 概述 本文档提供了一份详细的现代维吾尔文字符集的Unicode编码表。这份表格对于理解、处理和展示维吾尔语文字具有重要意义。通过这份表格,我们可以清晰地看到每一个维吾尔文...
本文以故事的形式介绍了字符集和编码的发展历程,从ASCII到Unicode和UTF-8编码。 ASCII,全称为American Standard Code for Information Interchange(美国信息交换标准代码),最初是基于8位字节的编码系统,可以...
总结来说,字符集和编码是处理文本的基础,Unicode字符集提供了一种全球通用的标准,而UTF-8编码则是一种高效且广泛使用的变长编码方式,能够有效地解决字符边界识别和内存利用的问题。在编程和数据处理领域,理解和...
字符集与字符集编码简介 我们知道,计算机只能识别诸如0101这样的二进制数,于是人们必须以二进制数据与计算机进行交互,或者先将人类使用的字符按一定规则转换为二进制数。 那什么是字符呢?在计算机领域,我们把...
在软件开发领域,字符集和编码转换是至关重要的概念,它们决定了程序如何正确处理和显示各种语言的文本。以下是对标题和描述中提到的几个关键知识点的详细解释: 1. **GB2312编码**:GB2312是中国大陆最早广泛使用...
文档中主要介绍了各类字符集以及相关的字符编码,字符的显示原理,从输入到显现的整个过程,程序中出现的乱码问题以及解决方案
Mysql字符集编码详解 Mysql数据库中的字符集编码问题是许多开发者经常遇到的一个问题,特别是在JAVA项目中。解决这个问题需要从多方面入手,包括服务器、数据库、数据表和连接等四个层次。这篇文章将详细介绍如何...
字符集和编码是计算机科学中不可或缺的一部分,它们确保了文本在不同系统和设备之间的一致性和可读性。随着全球化的发展和技术的进步,Unicode已成为事实上的标准,其广泛的字符覆盖和灵活的编码方式使其成为现代...