计算机 编码 解码

目录

  • 1 字符 & 编码
  • 2 记事本下的乱码
  • 3 UTF-8解码过程
  • 4 UTF-16解码过程
  • 5 ISO-8859-1
  • 6 byte范围

在阅读本文章之前,我建议你首先看阮一峰的博客:http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html

1 字符 & 编码

字符:

是文字和符号的总称。一个汉字、标点符号、英文字母、数字,这都是字符

字符集:

是多个字符的集合。我们可以理解为一本大字典。字符集种类很多,每个字符集包含的字符个数也不同。常见的字符集有:ASCII字符集、Unicode字符集、GB2312字符集、ISO-8859-1字符集等

字符编码:

计算机只能识别二进制1和0。字符集中的字符,计算机是不能直接识别的,所以要将字符集转换为计算机可以识别的二进制,这个转换过程就是编码,而字符编码就是将二进制的数与字符集中的字符对应起来的一套规则

全角和半角(针对中文字符集):

中文字符集将ASCII里本来就有的大小写英文字母、阿拉伯数字、标点符号重新编写了一套两个字节长的编码,这就是 “ 全角 ”字符,而原来在127以下的那些就叫 “ 半角 ”字符了。全角和半角只针对于字母、数字和标点而言的,对于中文字是没有全角和半角区分的。

全角字符:字母和数字与汉字占等宽位置的字并且占2个字节 半角字符:正常ASCII字体宽度且占一个字节

全角字符:abcdef123  -- 字体要宽一点   总共有18个字节
半角字符:abcedf123        -- 字体要窄一点   总共有 9个字节

GB2312、GBK、GB18030区别:

GB2312支持的汉字太少。1995年的汉字扩展规范GBK1.0收录了21886个符号,它分为汉字区和图形符号区。汉字区包括21003个字符。2000年的GB18030是取代GBK1.0的正式国家标准。该标准收录了27484个汉字,同时还收录了藏文、蒙文、维吾尔文等主要的少数民族文字。现在的PC平台必须支持GB18030,对嵌入式产品暂不作要求。所以手机、MP3一般只支持GB2312。

从ASCII、GB2312、GBK到GB18030,这些编码方法是向下兼容的,即同一个字符在这些方案中总是有相同的编码,后面的标准支持更多的字符。在这些编码中,英文和中文可以统一地处理。区分中文编码的方法是高字节的最高位不为0。按照程序员的称呼,GB2312、GBK到GB18030都属于双字节字符集 (DBCS)。

Unicode汉字范围:

Unicode采用两字节表示,因此总共能表示65536个字符,汉字的开始编号是 19968,十六进制表示 \u4E00,最后一个汉字的位置编号是40869,十六进制表示 \u9FA5。[\u4E00-\u9FA5]

Unicode中每个字符的编码都是2个字节,包括英文字母、数字。

2 记事本下的乱码

我们知道在window下记事本,输入联通,然后保存再打开,会出现乱码情况,以前只知道是GB2312和UTF-8编码冲撞了,并没有认真研究底层原理,今天我们就一起来看看真正的原因是什么。

当新建一个文本文件的时候,记事本的编码默认是ANSI编码

ANSI是一种字符编码标准,其实就是各个国家或地区的国标。对于中国地区就是GB2312编码,中国台湾地区就是BIG5编码,对于日本就是JIS编码,对于美国自然就是ASCII码等等。

如果在ANSI的编码输入汉字,那么他实际就是GB2312系列的编码,在这种编码下,”联通“的十六进制和二进制编码是:

C1 1100 0001

AA 1010 1010

CD 1100 1101

AB 1010 1000

如果大家不知道如何获取指定编码字符的二进制,可以通过程序来处理,也可以通过文本编辑器查看。这里我是通过Java程序来获取 “联通” 在GB2312下的二进制

public class Demo {
    public static void main(String[] args) throws Exception {
        String str = "联通";
        byte[] bytes = str.getBytes("GB2312");
        for (byte b : bytes) {
            System.out.print(Integer.toBinaryString(b) +"\r\n");
        }
    }
}

输出结果:

1111111111111111111111111 1000001
1111111111111111111111111 0101010
1111111111111111111111111 1001101
1111111111111111111111111 0101000

这里要注意,因为调用的是Integer.toBinaryString(b),而一个int在Java中占4个字节,byte只占一个字节,所以前三个字节全都是1,我们只用关注后面8位即可。

如果你看了 阮一峰 的博客,那么你现在已经知道了UTF-8的编码规则

Unicode符号范围     |        UTF-8编码方式
(十六进制)          |              (二进制)
----------------------+---------------------------------------------
0000 0000-0000 007F | 0xxxxxxx           !!!第一类
0000 0080-0000 07FF | 110xxxxx 10xxxxxx  !!!第二类
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

记事本保存联通的二进制为:

1100 0001 1010 1010

1100 1101 1010 1000

这刚好和UTF-8第二类编码一致,所以这个时候,记事本就会误以为该文件应该以UTF-8编码的方式打开,然后就按照UTF-8的方式处理这些二进制,因为前两个字节 1100 0001 1010 1010的实际有效位数是00001 101010,转换成十六进制是6a,但是6a却属于第一类,这个时候就产生乱码了。因此,平常开发尽可能少使用txt。

3 UTF-8解码过程

有一个UTF-8编码的文本,文本内容如下:

aá一

分别是英文字母a,发育字母á,中文汉字一

一:获取十六进制编码

通过16进制工具,查看16进制编码(我本人使用的是Sublime 插件 hexViewer)

61 c3 a1 e4 b8 80

二:计算二进制编码

01100001

11000011

10100001

11100100

10111000

10000000

三:根据UTF-8编码规则将字节分组后:

01100001

11000011

10100001

11100100

10111000

10000000

四:重新计算,得出对应的Unicode字符集的二进制编码

00000000 01100001 注意在Unicode中是两个字节表示一个字符,因此这里会补 00000000

00000000 11111001

01001110 00000000

五: 计算机从Unicode中查询出字符集为

a

á

4 UTF-16解码过程

aá一 这三个字符,不过这次是用UTF-16 BE保存的,及大头模式,如果对大头和小头方式不清楚的,请先看阮一峰的博客

一:获取十六进制编码

通过16进制工具,查看16进制编码(我本人使用的是Sublime 插件 hexViewer)

fe ff 00 61 00 e1 4e 00

fe ff表示的是UTF-16 大头模式,仅仅用于标记字节顺序,不表示具体的字符。

二:计算二进制编码

00000000

01100001

00000000

11100001

01001110

00000000

三:根据UTF-16编码规则将字节分组后:

UTF-16两个字节表示一个字符,即使是ASCII也是这样。

00000000 01100001

00000000 11100001

01001110 00000000

因为Unicode定义的标准就是两个字节表示一个字符,而UTF-16具体实现刚好就是用两个字节表示一个字符,因此这里就不需要再进行处理了

四:计算机从Unicode中查询出字符集为

a

á

Unicode将世界上的文字和二进制一一对应起来,并规定2个字节表示一个字符。

但是没有规定这个二进制代码应该如何存储,并且在网络上如何传输。

而UTF-8和UTF-16定义了这些二进制代码应该如何存储,并且在网络上如何传输。不过最后,程序都会按照UTF-8和UTF-16的规则去解析这些二进制,然后转换成Unicode,然后再通过一一对应,查找到该字符。

无论是UTF-8还是UTF-16编码的字符,最后转换成Unicode字符的二进制都是一样的,因为他们遵循同一个Unicode标准。

5 ISO-8859-1

以前开发JSP的时候,默认就是ISO-8859-1编码。

ASCII只能表示128个字符,而一个字节能够表示256种字符,ASCII编码浪费了一个字节接近一半的空间。

所以ISO-8859-1扩展了ASCII编码,在ASCII编码之上又增加了西欧语言、希腊语、泰语、阿拉伯语、希伯来语对应的文字符号,它是向下兼容ASCII编码的。

因为ISO-8859-1编码范围使用了单字节内的所有空间,在支持ISO-8859-1的系统中传输和存储其他任何编码的字节流都不会被抛弃。换言之,把其他任何编码的字节流当作ISO-8859-1编码看待都没有问题。这是个很重要的特性,MySQL数据库默认编码是Latin1就是利用了这个特性。ASCII编码是一个7位的容器,ISO-8859-1编码是一个8位的容器。

6 byte范围

在整理字符研究的时候,发现一个问题

public class Demo {
    public static void main(String[] args) throws Exception {
        String str = "联通";
        byte[] bytes = str.getBytes("GB2312");
        for (byte b : bytes) {
            System.out.println(b);
        }
    }
}

输出:

-63
-86
-51
-88

刚开始的时候,不是很理解为什么Java程序会输出负值。想了一下,忽然想起在Java中

byte范围 -128-127

而bytes中保存的二进制是

1100 0001

1010 1010

1100 1101

1010 1000

最高位的1,Java中的byte无法处理,只能当做符号位,以补码存储。

参考资料:
http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html

https://pcedu.pconline.com.cn/empolder/gj/other/0505/616631_all.html#content_page_2

作者:一杯热咖啡AAA

出处:https://www.cnblogs.com/AdaiCoffee/

本文以学习、研究和分享为主,欢迎转载。如果文中有不妥或者错误的地方还望指出,以免误人子弟。如果你有更好的想法和意见,可以留言讨论,谢谢!

原文地址:https://www.cnblogs.com/AdaiCoffee/p/11623557.html

时间: 2024-09-30 14:54:07

计算机 编码 解码的相关文章

Base64编码解码算法

Base64不是什么新奇的算法了,不过如果你没从事过页面开发(或者说动态页面开发,尤其是邮箱服务),你都不怎么了解过,只是听起来很熟悉. 对于黑客来说,Base64与MD5算法有着同样的位置,因为电子邮箱(e-mail)正文就是base64编码的. 那么,我们就一起来深入的探讨一下这个东东吧. 对于一种算法,与其问"它是什么?",不如问"它实现了什么?" Base64实现了:将任意字节转为可读字符的编码. 我们知道,除了页面上的文本,计算机中的数据还有很多是不可见的

基本用法:5《编码/解码》《文件读写:<文本/图片/音频/Excel/E-mail>》

5 <编码/解码><文件读写:<文本/图片/音频/Excel/E-mail>> (1)最小单位(比特)bit,最常用单位(字节B)byte:  1B=8 bit--手机流量就是这么计算的 百兆宽带(100bit/s)下载速度只有十几兆((100/8)B/s),因为计数单位不一样 (2)编码表(计算机世界字典) 是人类自然语言和机器语言沟通的桥梁 (3)编码方式'Unicode'和'UTF-8' [Unicode]是内存编码的规范,占用内存大:[UTF-8]是硬盘存储和传

Python8_关于编码解码和utf-8

关于编码:ASCII码是早期的编码规范,只能表示128个字符.7位二进制数表示 扩展ASCII码,由于ASCII码不够用,ASCII表扩充到256个符号,不同的国家有不同的标准:8位二进制数 Unicode 准确来说不是编码格式,而是字符集.这个字符集包含了世界上所有的符号所有字符长度统一用16位表示,因此字符是定长的: GB2312 在ASCII码表的基础上,小于127的字符意义与原来相同,而将大于127的字节连在一起,表示汉字前一个字节从0xA1(161)到0xF7(247)共87个,称为高

[C语言]Base64编码解码

Base64编码解码 一,Base64编码原理 Base64编码的字符数组如下所示 : ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ 字符串转Base64编码:取3字节的字符串转换为四字节的字符串,依次往后转换.得到Base64编码字符串.具体原理如下: 1,如果需要编码的原串字节数刚好为3的倍数,那么转换规则如下: 以中文字符'严'为例,'严'字的UTF-8编码为:0xE4B8A5 = 11100100  10

服务器端获取表单数据的编码解码问题(servlet)

首先需要明确指出的是,这里的服务器是指tomcat. 在页面没有明确指定编码的情况下,客户端通过input标签和字符串向服务器传递两个值param1和param2.如果直接使用request.getParameter()方法来获取值的话,得到的肯定都是乱码,我们需要对其重新进行编码解码,就像下面的代码所示的那样: new String(req.getParameter("param1").getBytes("iso-8859-1"), "gbk"

百度移动版的url编码解码代码

1 var decode = function(m) { 2 try { 3 m = decodeURIComponent(m); 4 } catch(e) {} 5 var s = m.split("%"); 6 if (s.length > 1) { 7 s.shift(); 8 for(var i = 0; i < s.length; i++) { 9 var t = s[i]; 10 t = parseInt(t, 16); 11 t = t + 256; 12 t

Atitit.&#160;二进制数据ascii表示法,与base64编码解码api&#160;设计标准化总结java&#160;php&#160;c#.net

Atitit. 二进制数据ascii表示法,与base64编码解码api 设计标准化总结java php c#.net 1. Base64编码,1 1.1. 子模式 urlsafe Or  url unsafe2 1.2. 其他的二进制数据表示法  bin2hex() ,Quoted-printable ,UUencode2 2. Base64常用api2 2.1. ------------解码api2 2.2. decode(String s, OutputStream out)2 2.3. 

使用多字节字符集的跨平台(PC、Android、IOS、WP)编码/解码方法

随着移动端的发展,跨平台已成为通讯架构设计的重要考虑因素,PC.Android.IOS.WP等跨多平台间的数据通讯,必然要解决字符编码/解码的问题. 多字节字符集MBCS不是跨平台的首选字符集,面向跨平台.国际化的推荐字符集肯定是UNICODE. 写VC的人都知道,在以前VC++6.0中默认的字符集是多字节字符集,而VS2005及以后默认的字符集是Unicode,VS2013中默认不再对多字节字符串进行支持. 但对很多较早的服务端项目,依然使用的是多字节字符集,不过使用多字节字符集依然可以实现跨

常见编码解码脚本

在平时我们会遇到各种各样的编码,在这里,我总结了一些常见的编码,并不是很全 尝试着做了个编码解码的汇总,并且写了个脚本出来,由于python功底不是很强,所以可能会有不到之处,还望各位多多指正 附上脚本: 1 #-*-coding:utf-8-*- 2 #author:hell0_w 3 #本人博客:http://hell0w.cnblogs.com/ 4 5 import base64 6 import bubblepy 7 import urllib 8 import quopri 9 im