概要
我们编辑一份代码的时候,会用一个文件来存储这份代码。用来存储的这个文件,有多种编码方式,常见的有utf-8、gb2312编码方式。当你在文件中写入某些特殊字符,例如中文的时候,计算机需要使用当前文件的编码方式来存储这些字符。因此,存储这些信息的格式,是以这种编码方式进行转译后的代码格式,而并非该字符本身。这种编码计算机可读,而人类不可读。
如果你刚接触计算机,可能会好奇,“明明我打开文件看到的就是我能理解的文本,并没有所谓我读不懂的东西。“是的,当你打开文本文件的时候,计算机肯定要给你你能看懂的文本,如果他给的是一堆看都看不懂的代码,你肯定要退货。所以,你所看到的文本,其实是文本文件这个程序通过你设定的那个编码格式,将代码文件转换成你能读懂的文本后结果。
编码方式相当于是一把钥匙,只有给对钥匙,计算机才能将代码正确解析成人类能看懂的文本。当我们需要将这种由人类不可读的代码重新转换为人类可读的文本时,我们需要告诉计算机,这种代码使用哪种类型的编码方式做的转换,计算机才能正确地将代码解析成正确的可读文本,否则,计算机会将代码做错误的解析,最终输出的文本我们称为乱码。
html
当我们要在浏览器中展现各种文字的时候,我们需要将一份代码文件交给浏览器去呈现。我们举个比较简单的例子,像我的博客,我的前端页面目前搭建的是一个静态站点,那么我要交给浏览器的这份代码文件必然是直接从某个文本中读取出来的。这个文件就是前文中所说的那个代码文件,它在创建或保存的时候就被指定了编码格式,因此,他所保存的内容就是以该编码格式进行编码后的代码结果。当我们需要把这些代码在浏览器中呈现的时候,我们同样需要告诉浏览器,这些文件是以什么编码格式做的编码。
这个时候,我们可能会有另外一个疑惑,我们保存代码的时候不是已经在文件中指定了该文件的编码格式吗,那我们将文本推送给浏览器的时候,不就清楚我们用的是什么格式的编码了吗?为什么还要再告诉浏览器我们用的是什么编码?也许只有我曾经犯过这个低级的错误!
其实我们推给浏览器的是这个文本中的内容,而文本文件的编码格式是以属性的方式存储在该文件相关的位置,并不存储在文本文件中。因此,当我们将这个文本文件的内容推给浏览器的时候,浏览器并不知道它是以什么样的编码格式存在的,为了保证浏览器能够解析文本内容,我们需要告诉浏览器这个文本文件的存储格式,告诉的方式就是<meta charset="???">
。
做一个测试,我们可以随便建立一个文本文件,以html为后缀,写入一段中文,双击打开后发现是一些乱码。是的,因为现代浏览器默认的编码格式是ISO-8859-1,而我们一般创建的文本文件是UTF-8编码(也有可能是gb2312等其它编码)。因为没有指定正确的编码格式,因此,网页以ISO-8859-1的解码方式去解了UTF-8编码后的代码文件,用错了钥匙,于是出现了乱码。这时候我们只要在指定<meta charset="UTF-8">
即可。
爬虫
为什么会写这篇文章呢?因为最近在做爬虫。爬到一个国外的站点,这个站点设置了charset="ibm866"
。根据我们爬虫的框架,在抓取到页面数据后,会用页面指定的charset去反编码页面。之前的站点都正常,出了这个站点。一执行反编码操作,页面内容全部变成乱码。很奇怪,于是我用curl尝试请求该页面,发现返回回来的数据在bash里面可以正常显示。内容与网页所见一致,由于bash本身是utf-8编码,于是我推断,该站点正确的编码格式应该是utf-8
而不是ibm866
,否则我的bash不可能正常解析。
疑问
于是,我产生了疑问,如果说文档的编码格式是UTF-8,而页面设置的编码格式是ibm866
,那根据常理来说应该会解析错误,导致页面出现乱码,但那个站点却显示正常。
为了搞清楚这个问题,我创建了一个UTF-8格式的html文件,写上一段中文,双击打开,乱码,预料之中。然后我把这个文件放到web服务器中去,通过http访问这个文件,这个文件正常显示中文了,我比较惊讶,浏览器默认编码格式并非UTF-8。接着,我试着将charset定义为各种错误的编码方法,结果都是正常显示中文字符。这个有点超过我的知识范围了,我在segmentfault提交了一个问题,如果你明白这个原理,请不吝赐教,谢谢!!