字符编码

 encoding  html-entities  unicode  urlencode  base64


字符编码

字符编码是自然语言到计算机语言的映射。计算机内部,所有信息最终都是一个二进制值,然而人类无法识别机器语言。因此,需要一套字符编码规则将自然语言映射到机器语言。

ASCII 编码

上个世纪60年代,美国制定了 ASCII 字符编码,该字符编码一共规定了128个字符的编码,对应英语字符与二进制位之间的映射关系。ASCII 码长度为一个字节,但只占用了一个字节的后面7位,最前面的一位统一规定为0。

Base64 编码

由于数据在网络传输过程中,不同的设备(路由器、浏览器、文本编辑器)对字符编码的处理方式不同,不被支持的字符编码可能被错误的处理。

计算机中任何数据都是按字节存储,ASCII编码长度为一个字节,ASCII 编码几乎被所有的设备支持,因此,Base64 编码的思路是将数据按比特流转码为ASCII可见字符编码。

Base64 编码的内容由0-9,a-z,A-Z,+,/组成,正好64个字符(6bit),这些字符在 ASCII 编码的可表示的范围内。

因此,将数据解析为比特流,如01000100…,并依次取6bit为一组并映射到上述的ASCII字符,循环往复直到最后编码完成。

Base64 编码的特点:

  1. 标准 Base64 只有64个字符(英文大小写、数字和+、/)以及用作后缀的等号;
  2. Base64 是把3个字节变成4个可打印的ASCII字符,所以 Base64 编码后的字符串一定能被4整除,并且编码后的长度变为原先的4/3;

Unicode 编码

Unicode与UTF-8的关系

Unicode 定义了世界上所有符号对应的二进制编码,并未规定二进制编码的存储实现方式。

UTF-8 是一种 Unicode 的实现方式,UTF-8 是一种变长的编码方式,根据符号的不同,使用1~4个字节表示一个符号。

UTF-8 符号
맟

UTF-8的编码规则

  1. 对单字节的符号,字节第一位为0,后面7位为这个符号的 Unicode 编码。因此对于英文字母,UTF-8 编码与Unicode 编码是相同的。
  2. 对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。
  字节1 字节2 字节3 字节4
1字节 0xxxxxxx      
2字节 110xxxxx 10xxxxxx    
3字节 1110xxxx 10xxxxxx 10xxxxxx  
4字节 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

UTF-8 BOM

BOM(byte order mark)是为 UTF-16 和 UTF-32 准备的,用于标记字节次序(byte order)。UTF-8 和 UTF-8 BOM 的区别就是有没有BOM,即文件开头有没有U+FEFF。UTF-8不需要BOM,尽管Unicode标准允许在UTF-8中使用BOM,所以不含BOM的UTF-8才是标准形式。

尽管UTF-8编码中不需要字节次序标识,但是将包含BOM的UTF-16、UTF-32数据转换为UTF-8编码时,会将BOM引入到UTF-8中,虽然引入的BOM编码不会影响UTF-8的显示,在转换JSON的时候或者网页展示可能存在问题,需要在处理时过滤掉,过滤处理方式如下:

trimLeft = /^[\s\xA0]+/;
trimRight = /[\s\xA0]+$/;
return text == null ? "" : text.toString().replace(trimLeft, "").replace(trimRight, "");

Unicode汉字编码范围

在unicode中,从0x4e00-0x9fa5,为常用的20902个汉字。例如,通过正则判断是否为5个汉字:

/^[\x{4e00}-\x{9fa5}]{5}$/u

程序处理编解码

Apache Commons Lang

StringEscapeUtils.unescapeJava()

HTML Entities 编码

在HTML中下述两类字符必须使用字符实体表示:

  1. 预留字符,如>、<、&等;
  2. 特殊字符,如©、♥、®等;【注:特殊字符即无法通过键盘输入的字符】

各浏览器厂商依照W3C标准针对预留字符与特殊字符制定的一套编码,即为字符实体;

Character Entity HTML Name HTML Decimal HTML Hex Description
&hearts &#9829 &#x02665 heart

URLEncode编码

使用浏览器进行Http网络请求时,若请求query中包含中文,中文会被编码为%+16进制+16进制形式,但你真的深入了解过,为什么要进行这种转移编码吗?编码的原理又是什么?

例如,浏览器中进行百度搜索“你好”时,链接地址会被自动编码:

  • (编码前)https://www.baidu.com/s?wd=你好
  • (编码后)https://www.baidu.com/s?wd=%E4%BD%A0%E5%A5%BD

出现以上情况是网络请求前,浏览器对请求URL进行了URL编码(URL Encoding)。

URL编码(URL Encoding):也称作百分号编码(Percent Encoding),是特定上下文的统一资源定位符 URL 的编码机制。URL编码(URL Encoding)也适用于统一资源标志符(URI)的编码,同样用于 application/x-www-form-urlencoded MIME准备数据。

为什么需要URL Encoding

在URL的最初设计时,希望可以通过书面转录,比如写在餐巾纸上告诉另外一人,因此URI的构成字符必须是可写的ASCII字符。 中文不在ASCII字符中,因此中文出现在URL地址中时,需要进行编码; 同时可书写的ASCII字符中,存在一些不安全字符也需要转码,如空格(空格容易被忽略,也容易意想不到的原因引入)。

https://www.ietf.org/rfc/rfc1738.txt

No corresponding graphic US-ASCII:

URLs are written only with the graphic printable characters of the US-ASCII coded character set. The octets 80-FF hexadecimal are not used in US-ASCII, and the octets 00-1F and 7F hexadecimal represent control characters; these must be encoded.

Unsafe:

Characters can be unsafe for a number of reasons. The space character is unsafe because significant spaces may disappear and insignificant spaces may be introduced when URLs are transcribed or typeset or subjected to the treatment of word-processing programs. The characters “<” and “>” are unsafe because they are used as the delimiters around URLs in free text; the quote mark (“””) is used to delimit URLs in some systems. The character “#” is unsafe and should always be encoded because it is used in World Wide Web and in other systems to delimit a URL from a fragment/anchor identifier that might follow it. The character “%” is unsafe because it is used for encodings of other characters. Other characters are unsafe because gateways and other transport agents are known to sometimes modify such characters. These characters are “{“, “}”, “|”, “", “^”, “~”, “[”, “]”, and “`”.

All unsafe characters must always be encoded within a URL. For example, the character “#” must be encoded within URLs even in systems that do not normally deal with fragment or anchor identifiers, so that if the URL is copied into another system that does use them, it will not be necessary to change the URL encoding.

xx

编码原理

编码的原理可以表述为: 将需要转码的字符,按指定编码方式(默认使用UTF-8编码)转化为字节流,每个字节按16进制表示,并添加%组成一个percent编码。例如:汉字 “你好”

  • UTF-8字节流打印为:[-28, -67, -96, -27, -91, -67]
  • 对应的16进制表示为:[E4, BD, A0, E5, A5, BD]
  • URLEncode编译后为:%E4%BD%A0%E5%A5%BD

编码范围

哪些字符需要转码

When encoding a String, the following rules apply:

  • The alphanumeric characters “a” through “z”, “A” through “Z” and “0” through “9” remain the same.
  • The special characters “.”, “-“, “*”, and “_” remain the same.
  • The space character “ “ is converted into a plus sign “+”.

All other characters are unsafe and are first converted into one or more bytes using some encoding scheme. Then each byte is represented by the 3-character string “%xy”, where xy is the two-digit hexadecimal representation of the byte. The recommended encoding scheme to use is UTF-8. However, for compatibility reasons, if an encoding is not specified, then the default encoding of the platform is used.

空格的编码规则

需要特别注意的是空格的编码有 “+”和“%20”两种。

  1. 空格编码为 + 的情况: 提交表单时请求时Content-Type:application/x-www-form-urlencoded的时,URL请求查询字符串中出现空格时,需替换为+;
  2. 空格编码为%20的情况:其他情况;

程序框架解码

在Java的Web容器处理请求时,在 request.getParameter(“name”) 之前会自动做一次解码的工作,而且是默认的 ISO-8859-1,相当于调用了一次 java.net.URLDecoder.decode(name, “ISO-8859-1”)。

URLEncode编码 与 HTML Entities编码的区别

HTML Encoding转义HTML文档中使用的字符串中的特殊字符,以防止与HTML元素混淆。 比如编码

<!-- 编码前 -->
<hello>world</hello>
<!-- 编码后 -->
&lt;hello&gt;world&lt;/hello&gt;

URL Encoding对URL中的字符串值做类似的事情。

<!-- 编码前 -->
hello+world = hello world
<!-- 编码后 -->
hello%2Bworld+%3D+hello+world