聊聊计算机中的编码(Unicode,GBK,ASCII,utf8,utf16,ISO8859-1等)

作为一个程序员,一个中国的程序员,想来“乱码”问题基本上都遇到过,也为之头疼过。出现乱码问题的根本原因是编码与解码使用了不同而且不兼容的“标准”,在国内一般出现在中文的编解码过程中。

我们平时常见的编码有Unicode,GBK,ASCII,utf8,utf16,ISO8859-1等,弄清这些编码之间的关系,就不难理解“乱码”出现的原因以及解决办法。

所谓字符集编码其实就是将字符(包括英文字符、特殊符号,控制字符,数字,汉子等)与计算机中的一个数字(二进制存储)一一对应起来,用这个数字来表示该字符,存储该字符的时候就存储这个数字。比如a对应数字97。因此,理解编码很简单,所有的编码都是字符与数字的一种对应关系

ASCII编码:

计算机最早出现在美国,因此老美搞编码只需要对26个英文字符大小写以及常用的字符对应数字就可以了,这种对应就是ASCII(American Standard Code for Information Interchange,美国信息互换标准代码)码。标准ASCII 码使用7 位二进制数来表示所有的大写和小写字母,数字0 到9、标点符号, 以及在美式英语中使用的特殊控制字符。这样可以表示27=128个字符。标准ASCII码的最高位恒为0,没有使用。

iso8859-1:

随着计算机的推广,世界各地都开始使用计算机。各国不同语言对字符编码提出了新的需求,原ASCII的128个字符已经显得严重不足。那怎么办呢,ASCII码不是只用了一个字节中的7位吗,还剩余1位呢?那就赶紧用上吧!于是人们把编码扩展到了8位,即256个字符的编码,这就是ISO8859-1。这种扩展保持了与ASCII的兼容性,即最高位为0的ISO8859-1编码等同于ASCII码。

GBK码:

等到计算机进入中国,人们又头疼了。常用汉字就有6000多个,像ASCII那样用一个字节来编码撑爆了也不够啊。但是这难不倒智慧的中国人们,我们直接定下标准:小于127的字符与原意义相同(保持与ASCII的兼容性),但是两个大于127的字符连在一起时,就表示一个汉字。这样我们就凑出来了7000多个简体汉字的编码了。此外,这些编码还对ASCII码中已有的标点、数字、字母都用两字节重新编码,这就是通常说的“全角”字符。这种编码就是GB2312

但是中国的汉字实在太多了,GB2312还是不够用,一些不常用的汉字还是显示不出来啊。于是我们不得不继续挖掘GB2312的潜能,干脆只要求第一个字节大于127而不管后一个字节的大小了。这种扩展之后的编码方案称为GBK

Unicode码:

中国造出了GBK编码,其他国家呢,他们也要显示自己的文字啊。于是各个国家都搞出了一套自己的编码标准,结果相互之间谁也不懂谁的编码,互不兼容。这样不行啊,于是乎ISO(国际标谁化组织)不得不站出来说话了:“你们都不要各自搞编码了,我给你们搞一套统一的!”。于是ISO搞了一个全球统一的字符集编码方案,叫UCS(Universal Character Set),俗称Unicode

Unicode标准最早是1991年发布了,目前实际应用的版本是UCS-2,即使用两个字节编码字符。这样理论上一共可以编码216=65536个字符,基本能够满足各种语言的需求。

UTF8、UTF16码:

其实Unicode码已经完美解决编码国际化问题了,那utf8和utf16又是神马东东,用来解决什么问题呢?

前面已经说过,编码只是字符与数字的一种对应关系,这完全是一个数学问题,跟计算机和存储以及网络都没有半毛钱关系。Unicode码就是这样一种对应关系,它并没有涉及到如何存储以及传输的问题。看下面一个例子:

假如某个字符的Unicode编码为0xabcd,也就是两个字节。那存储的时候是哪个字节在前哪个在后呢?网络传输的时候又是先传输哪个字节呢?计算机从文件中读取到0xabcd又是怎么知道这是两个ASCII码还是一个Unicode码呢?

因此需要一种统一的存储和传输格式来标示Unicode码。这种统一的实现方式称为Unicode转换格式(Unicode Transformation Format,简称为UTF)。编码utf8和utf16就是因此而产生的。

其中utf16与16位的Unicode码完全对应。在Mac和普通PC上,对于字节顺序的理解是不一致的。比如MAC是从低字节开始读取的,因此前文的0xabcd如果按照所见的顺序存储,则会被MAC认为是0xcdab,而windows会从高字节开始读取,得到的是0xabcd,这样根据Unicode码表对应出来的字符就不一致了。

因此,utf16使用了大端序(Big-Endian,简写为UTF-16 BE)、小端序(Little-Endian,简写为UTF-16 LE)以及BOM(byte order mark)的概念。如果在windows上用记事本写上一些中文字符并以Unicode码格式保存,然后使用十六进制查看器打开即可以看到文件的前两个字节为0xfffe(0xfffe在Unicode码中不对应字符),用来标记使用小端序存储(windows平台默认使用小端序),下图为中文“你好”二字在windows7上的十六进制数据。

由于Unicode统一采用16位二进制编码字符,试想一篇英文文章如果用UTF16来存储的话整整比用ASCII存储多占用一倍的存储空间(英文字符的Unicode码高字节是0),这样白白的浪费让人于心不忍啊。于是utf8诞生了。utf8是一种变长编码,根据不同的Unicode码值采用不同的存储长度。那么问题又来了,既然是变长的系统怎么知道几个字节表示一个字符编码呢?对于这类问题计算机中通用的处理方式就是使用标志位,就像ip段的划分一样。具体如下:

0xxxxxxx,如果是这样的01串,也就是以0开头后面是啥就不用管了XX代表任意bit.就表示把一个字节做为一个单元.就跟ASCII完全一样.

110xxxxx 10xxxxxx.如果是这样的格式,则把两个字节当一个单元

1110xxxx 10xxxxxx 10xxxxxx 如果是这种格式则是三个字节当一个单元.

由于utf8可能不止一个字节,因此存储时同样需要标记从哪端读取之类的,因此类似utf16编码,utf8同样有大端序、小端序和BOM的概念。

Unicode码的发展

Unicode码采用16位编码世界字符其实还是有点捉襟见肘的。因此从 Unicode 3.1 版本开始,设立了16个辅助平面(相当于Unicode码又扩充了4位),使 Unicode 的可使用空间由六万多字增至约一百万字。用白话说就是增加了几个区段,比如原始版本的Unicode码的范围是0x0000 ~ 0xffff,第一辅助平面的范围是0x10000~0x1FFFD,第二辅助平面的范围是0x20000 ~ 0x2FFFD,……

最新版的Unicode码规范提出了UCS-4,即使用4字节做Unicode编码。类似前面的utf16,对于UCS-4的Unicode码,可以采用utf32来存储,同样需要定义大小端序和BOM信息。

时间: 2024-12-26 17:07:03

聊聊计算机中的编码(Unicode,GBK,ASCII,utf8,utf16,ISO8859-1等)的相关文章

Android中检测字符编码(GB2312,ASCII,UTF8,UNICODE,TOTAL——ENCODINGS)方法(一)

package com.android.filebrowser; import java.io.*; import java.net.*; public class FileEncodingDetect { static final int GB2312 = 0; static final int ASCII = 1; static final int UTF8 = 2; static final int UNICODE = 3; //static final int GBK = 4; //st

Android中检测字符编码(GB2312,ASCII,UTF8,UNICODE,TOTAL——ENCODINGS)方法(二)

Intent intent = getIntent(); String contentUri = null; Uri uri =null; if (intent.getData() != null) { uri = intent.getData(); contentUri = "file".equals(uri.getScheme()) ? FileContentProvider.BASE_URI + uri.getEncodedPath() : uri.toString(); Str

计算机中的编码问题

计算机中的编码问题 因为计算机只能处理数字,如果要处理文本,就必须先把文本转换为数字才能处理.最早的计算机在设计时采用8个比特(bit)作为一个字节(byte),所以,一个字节能表示的最大的整数就是255(二进制11111111=十进制255),如果要表示更大的整数,就必须用更多的字节.比如两个字节可以表示的最大整数是65535,4个字节可以表示的最大整数是4294967295. 一.目前常用的编码 ASCII编码:由于计算机是美国人发明的,因此,最早只有127个字母被编码到计算机里,也就是大小

Python Solve UnicodeEncodeError 'gbk' / 'ascii' / 'utf8' codec can't encode character '\x??' in position ? 解决有关Python编码的错误

在Python中,处理中文字符一直是很令人头痛的问题,一言不合就乱码,而且引起乱码的原因也不尽相同,有时候是python本身默认的编码器设置的不对,有时候是使用的IDE的解码器不对,还有的时候是终端terminal的解码器不对,有时候同一份代码在Python2上正常运行,Python3上就不行了,反正产生乱码的原因很多,这里就列举一些博主遇到过的一些错误及其解决方案: Error 1: UnicodeEncodeError: 'gbk' codec can't encode character

Android中检測字符编码(GB2312,ASCII,UTF8,UNICODE,TOTAL——ENCODINGS)方法(一)

package com.android.filebrowser; import java.io.*; import java.net.*; public class FileEncodingDetect { static final int GB2312 = 0; static final int ASCII = 1; static final int UTF8 = 2; static final int UNICODE = 3; //static final int GBK = 4; //st

Java 中文字符串编码之GBK转UTF-8

写过两篇关于编码的文章了,以为自己比较了解编码了呢?! 结果今天又结结实实的上了一课. 以前转来转去解决的问题终归还是简单的情形.即iso-8859-1转utf-8,或者iso-8859-1转gbk,gb2312之类.这种无损转换,一行代码就搞定. 今天遇到了gbk转utf-8.无论怎么转,都是乱码. 一.乱码的原因 gbk的中文编码是一个汉字用[2]个字节表示,例如汉字"内部"的gbk编码16进制的显示为c4 da b2 bf utf-8的中文编码是一个汉字用[3]个字节表示,例如汉

如何将Java源代码文件的编码从GBK转为UTF-8?

有时候看到有意思的demo,在头痛导入项目的编码和workspace的编码不一样的时候 我试着将 笔记本打开一个类一个类的复制, demo的类比较少的时候 可以忍受,demo的类多的时候 除了靠之外 别无办法 今天再找仿ios样式demo的时候 实在受不了乱码,新浪一搜,出现给力的工具类 大致思路 挺简单的 无非是找到路径 重新转码.谢谢 作者,尊重原创. http://blog.sina.com.cn/s/blog_7e4ac8b501019ujd.html

写一个脚本批量转换项目中GB2312编码的文件为UTF-8编码

#!/bin/bash convert_file() { for file in `find .` do if [[ -f $file ]] then if [[ ${file##*.} == lua || ${file##*.} == ini ]]; then iconv -f GB2312 -t UTF-8 $file >> $file echo $file fi fi done } convert_file 原文地址:https://www.cnblogs.com/praglody/p/

将UTF-8编码的文件读出,保存到编码为GBK的文件中

1 import java.io.BufferedReader; 2 import java.io.BufferedWriter; 3 import java.io.FileInputStream; 4 import java.io.FileNotFoundException; 5 import java.io.FileOutputStream; 6 import java.io.IOException; 7 import java.io.InputStreamReader; 8 import