字符编码
计算机内部,所有信息最终都是由二进制值表示。
字符编码就是将自然语言转换成计算机语言的编码规范。
一、ASCII 码
ASCII 码一共规定了128个字符的编码,包含大小写英文字母、数字和一些符号,比如空格SPACE
是32(二进制00100000
),大写的字母A
是65(二进制01000001
)。这128个符号(包括32个不能打印出来的控制符号),只占用了一个字节的后面7位,最前面的一位统一规定为0
。
二、Unicode与UTF-8
英语用128个符号编码就够了,但是用来表示其他语言,128个符号是不够的。中文至少需要两个字节,而且还不能和ASCII编码冲突,所以,中国制定了GB2312
编码,使用两个字节表示一个汉字,理论上最多可以表示 256 x 256 = 65536 个符号。
但全世界有上百种语言,日本把日文编到Shift_JIS
里,韩国把韩文编到Euc-kr
里,各国有各国的标准,就会不可避免地出现冲突,结果就是,在多语言混合的文本中,显示出来会有乱码。
因此,Unicode字符集应运而生。Unicode把所有语言都统一到一套编码里,这样就不会再有乱码问题了。Unicode标准也在不断发展,但最常用的是UCS-16编码,用两个字节表示一个字符(如果要用到非常偏僻的字符,就需要4个字节)。
ASCII编码和Unicode编码的区别:
- ASCII编码是1个字节,而Unicode编码通常是2个字节。
新的问题又出现了:如果统一成Unicode编码,乱码问题从此消失了。但是,如果文本基本上全部是英文的话,用Unicode编码比ASCII编码需要多一倍的存储空间。
因此将Unicode编码转化“可变长编码”的UTF-8
编码应运而生。这里的关系是,UTF-8 是 Unicode 的实现方式之一。
UTF-8编码把一个Unicode字符根据不同的数字大小编码成1-6个字节,常用的英文字母被编码成1个字节,汉字通常是3个字节,只有很生僻的字符才会被编码成4-6个字节。如果你要传输的文本包含大量英文字符,用UTF-8编码就能节省空间。
目前计算机系统通用的字符编码工作方式:
-
在计算机内存中,统一使用Unicode编码,当需要保存到硬盘或者需要传输的时候,就转换为UTF-8编码。
-
用记事本编辑的时候,从文件读取的UTF-8字符被转换为Unicode字符到内存里,编辑完成后,保存的时候再把Unicode转换为UTF-8保存到文件。
-
浏览网页的时候,服务器会把动态生成的Unicode内容转换为UTF-8再传输到浏览器。
UTF-8 编码规则:
- 对于单字节的符号,字节的第一位设为
0
,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。 - 对于
n
字节的符号(n > 1
),第一个字节的前n
位都设为1
,第n + 1
位设为0
,后面字节的前两位一律设为10
。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。
下表总结了编码规则,字母x
表示可用编码的位。
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
根据上表,解读 UTF-8 编码非常简单。如果一个字节的第一位是0
,则这个字节单独就是一个字符;如果第一位是1
,则连续有多少个1
,就表示当前字符占用多少个字节。
以汉字严
为例,演示如何实现 UTF-8 编码:
严
的 Unicode 是4E25
(100111000100101
),根据上表,可以发现4E25
处在第三行的范围内(0000 0800 - 0000 FFFF
),因此严
的 UTF-8 编码需要三个字节,即格式是1110xxxx 10xxxxxx 10xxxxxx
。然后,从严
的最后一个二进制位开始,依次从后向前填入格式中的x
,多出的位补0
。这样就得到了,严
的 UTF-8 编码是11100100 10111000 10100101
,转换成十六进制就是E4B8A5
。
三、URL编码
URL编码(URL encoding),也称作百分号编码(Percent-encoding), 是特定上下文的统一资源定位符的编码机制。
URL编码是一种浏览器用来打包表单输入的格式。浏览器从表单中获取所有的name和其中的值 ,将它们以name/value参数编码(移去那些不能传送的字符,将数据排行等等)作为URL的一部分或者分离地发给服务器。不管哪种情况,在服务器端的表单输入格式如下:
theName=Ichabod+Crane&gender=male&status=missing& ;headless=yes
URL编码规则:
-
每对name/value由&;符分开;每对来自表单的name/value由=符分开。如果用户没有输入值给这个name,那么这个name还是出现,只是无值。
-
任何特殊的字符(非七位的ASCII,如汉字)将以百分符%用十六进制编码,当然也包括像
=
&
;
和%
这些特殊的字符。URL编码具体以UrlEncode
函数实现,将需要转码的字符转为16进制,然后从右到左,取4位(不足4位直接处理),每2位做一位,前面加上%,编码成%XY
格式。
其实URL编码就是一个字符ASCII码的十六进制。不过稍微有些变动,需要在前面加上“%”。比如“\”,它的ascii码是92,92的十六进制是5c,所以“\”的URL编码就是%5c。
四、HTML实体符号编码
在 HTML 中,某些字符是预留的。例如<
和>
,这是因为在浏览器中会被误认为它们是标签。HTML 中的预留字符必须被替换为字符实体。
-
HTML 实体是一段以连字号(&)开头、以分号(;)结尾的文本(字符串)。
-
实体常常用于显示保留字符(这些字符会被解析为 HTML 代码)和不可见的字符(如“不换行空格”)。
简单来说,为了避免浏览器解析时混淆使用者输入的字符与HTML的语法,规定如果要输入HTML语法中的预留字符就要使用字符实体来替代。例如要显示小于号,必须这样写:<
或 <
。
常用的HTML字符实体
显示结果 | 描述 | 实体名称 | 实体编号 |
---|---|---|---|
空格 | |   | |
< | 小于号 | < | < |
> | 大于号 | > | > |
& | 和号 | & | & |
" | 引号 | " | " |
’ | 撇号 | ' (IE不支持) | ' |
¢ | 分 | ¢ | ¢ |
£ | 镑 | £ | £ |
¥ | 人民币/日元 | ¥ | ¥ |
€ | 欧元 | € | € |
§ | 小节 | § | § |
© | 版权 | © | © |
® | 注册商标 | ® | ® |
™ | 商标 | ™ | ™ |
× | 乘号 | × | × |
÷ | 除号 | ÷ | ÷ |
需要注意的是,虽然 HTML 不区分大小写,但实体字符对大小写敏感。