UTF8文件带BOM引起的问题——iOS端竟然加载出了html代码
起因是公司iOS端竟然加载出来了HTML代码,百思不得其解,查文献,原来如此...
UTF-8 不需要 BOM,尽管 Unicode 标准允许在 UTF-8 中使用 BOM。
所以不含 BOM 的 UTF-8 才是标准形式,在 UTF-8 文件中放置 BOM 主要是微软的习惯(顺便提一下:把带有 BOM 的小端序 UTF-16 称作「Unicode」而又不详细说明,这也是微软的习惯)。
BOM(byte order mark)是为 UTF-16 和 UTF-32 准备的,用于标记字节序(byte order)。微软在 UTF-8 中使用 BOM 是因为这样可以把 UTF-8 和 ASCII 等编码明确区分开,但这样的文件在 Windows 之外的操作系统里会带来问题。
「UTF-8」和「带 BOM 的 UTF-8」的区别就是有没有 BOM。即文件开头有没有 U+FEFF。
UTF-8 的网页代码不应使用 BOM,否则常常会出错。这是一个小例子: 为什么这个网页代码 <head> 内的信息会被浏览器理解为在 <body> 内?
另附《The Unicode Standard, Version 6.0》之 3.10 D95 UTF-8 encoding scheme 的一段话:
While there is obviously no need for a byte order signature when using UTF-8, there are occasions when processes convert UTF-16 or UTF-32 data containing a byte order mark into UTF-8. When represented in UTF-8, the byte order mark turns into the byte sequence. Its usage at the beginning of a UTF-8 data stream is neither required nor recommended by the Unicode Standard, but its presence does not affect conformance to the UTF-8 encoding scheme. Identification of the byte sequence at the beginning of a data stream can, however, be taken as a near-certain indication that the data stream is using the UTF-8 encoding scheme.
http://www.unicode.org/versions/Unicode6.0.0/ch03.pdf
---------------------------------------------------------
首先,BOM是啥。这个就不解释了,Wikipedia上很详细。http://en.wikipedia.org/wiki/Byte_order_mark。
在网页上使用BOM是个错误。BOM设计出来不是用来支持HTML和XML的。要识别文本编码,HTML有charset属性,XML有encoding属性,没必要拉BOM撑场面。虽然理论上BOM可以用来识别UTF-16编码的HTML页面,但实际工程上很少有人这么干。毕竟UTF-16这种编码连ASCII都双字节,实在不适用于做网页。
其实说BOM是个坏习惯也不尽然。BOM也是Unicode标准的一部分,有它特定的适用范围。通常BOM是用来标示Unicode纯文本字节流的,用来提供一种方便的方法让文本处理程序识别读入的.txt文件是哪个Unicode编码(UTF-8,UTF-16BE,UTF-16LE)。Windows相对对BOM处理比较好,是因为Windows把Unicode识别代码集成进了API里,主要是CreateFile()。打开文本文件时它会自动识别并剔除BOM。Windows用这个有历史原因,因为它最初脱胎于多代码页的环境(ANSI环境)。而引入Unicode时Windows的设计者又希望能在用户不注意的情况下同时兼容Unicode和非Unicode(Multiple byte)文本文件,就只能借助这种小trick了。相比之下,Linux这样的系统在多locale的环境中浸染的时间比较短,再加上社区本身也有足够的动力轻装前进(吐槽:微软对兼容性的要求确实是到了非常偏执的地步,任何一点破坏兼容性的做法都不允许,以至于很多时候是自己绑住自己的双手),所以干脆一步到位进入UTF-8。当然中间其实有一段过渡期,比如从最初全UTF-8的GTK+2.0发布到基本上所有GTK开发者都弃用多locale的GTK+1.2,我印象中至少经历了三到四年。
BOM不受欢迎主要是在UNIX环境下,因为很多UNIX程序不鸟BOM。主要问题出在UNIX那个所有脚本语言通行的首行#!标示,这东西依赖于shell解析,而很多shell出于兼容的考虑不检测BOM,所以加进BOM时shell会把它解释为某个普通字符输入导致破坏#!标示,这就麻烦了。其实很多现代脚本语言,比如Python,其解释器本身都是能处理BOM的,但是shell卡在这里,没办法,只能躺着也中枪。说起来这也不能怪shell,因为BOM本身违反了一个UNIX设计的常见原则,就是文档中存在的数据必须可见。BOM不能作为可见字符被文本编辑器编辑,就这一条很多UNIX开发者就不满意。
顺便说一句,即使脚本语言能处理BOM,随处使用BOM也不是推荐的办法。各个脚本语言对Unicode的处理都有自己的一套,Python的 # -*- coding: utf-8 -*-,Perl的use utf8,都比BOM简单而且可靠。另一个好消息是,即使是必须在Windows和UNIX之间切换的朋友也不会悲催。幸亏在UNIX环境下我们还有VIM这种神器,即使遇到BOM挡道,我们也可以通过 set nobomb; set fileencoding=utf8; w 三条命令解决问题。
最后回头想想,似乎也真就只有Windows坚持用BOM了。
P.S.:本问题是自己的第150个回答。突然发现自己回答得很少很少⋯⋯
P.S. 2:突然想起需要解释一下为什么说VIM去除bomb的操作需要在UNIX下完成。因为VIM在Windows环境下有一个奇怪的bug,总是把UTF-16文件识别成二进制文件,而UNIX(Linux或者Mac都可以)下VIM则无问题。这个问题从VIM 6.8一直跟着我到VIM 7.3。目前尚不清楚这是VIM的bug还是我自己那个.vimrc文件的bug。如有高手解答不胜感激。
---------------------------------------------------------
有bom格式在开头会多出3个字节 EF BB BF ,主要用于识别编码。bom应该是windows特有的,在制作网页时会产生各种意想不到的问题,例如多输出了一个空行,影响PHP的session或者cookies功能(出现 header already sent错误),甚至可能引起页面的乱码(那3个字节影响了浏览器对页面编码的处理),因此总是推荐使用无bom编码。为了处理这个问题我甚至写了一个批量处理的PHP脚本。
---------------------------------------------------------
邸强,软件开发ing
张旭东、Mingyue Zhou、sapjax 赞同
几周前还在为BOM的问题苦恼着。。。
正如@梁海所说,“不含 BOM 的 UTF-8 才是标准形式”,的确是这样,无BOM使用得更多些,所以个人还是推荐一般情况下用无BOM的形式吧,除非有问题的时候,再考虑换有BOM的。Windows系统保存的都是有BOM的,所以你可以看到,用记事本保存一个UTF-8的txt,其实是有BOM的,这一点需要注意。另外不同的文本编辑器对于有无BOM的称呼也略有不同,比如EditPlus,有BOM的称为UTF-8+,无BOM的称为UTF-8,而在Notepad++中,有BOM的被称为标准UTF-8,而无BOM则被称为UTF-8无BOM。
---------------------------------------------------------
武龙飞,c/c++ 程序员,喜欢天文学,数学和心理学。
Weijing Huang、Bill Chan、icky R 赞同
以下文字出自我的博客内容,从另一面解说不一样的bom。
---------------------------------------------------------
字符编码相信是每个程序员的噩梦,只要是有中文的地方,总是会遇到各种编码的问题,并且这种问题还非常难缠,尤其在linux上,因为上面很多软件都是针对英语国家开发的,是不会考虑其他语种编码问题。在遇到编码的无数大坑之后,我决定仔细研究下编码问题,因为这就像一道坎一直横在你面前,每次到这里你都会跌到,每次爬起来之后,你都若无其事,这样的人被称作战士,真正的战士。可惜是个力量战士,做为新时代的智力战士,当然不能在那跌到然后又在这继续跌到。
文件的存储方式:
文件都有自己的存储格式,比如最常见的txt,cpp,h,c,xml ,png, rmvb各种格式,还有自定义格式。这些文件不论是什么格式,都是存储在计算机硬盘里的2进制格存储,对应不同文件格式,有不同的软件解析。这篇文章不谈文件是如何存储的,只谈文件是如何解析的。
文本文件解析:
文本文件对应于人类可以阅读的文本,如何从2进制转换为文本文件呢?起初由于计算机在美国发明,自然大家考虑的是英语如何表示,英语字母总共26个,加上特殊字符,128个字符,7位既一个byte即可表示出来。这个就是大家所熟知的ascill编码。对应关系很简单,一个字符对应一一个byte。
但很快发现,其他非英语国家的文字远远超过ascill码,这时候大家当然想统一一下,不同国家出了自己不同的编码方式,中国的gb2312就是自己做出来的编码方式,这样下去每个国家都有自己的编码方式,来回转换太麻烦了。这时候出现了新的编码方式,unicode编码方式,想将编码统一,所以规定了每个字符对应的unicode码。
1、很多文件都是ascii编码,如果用unicode 太浪费。
2、没有标志位说明该几个字节来解析为一个符号。
这时候拯救世界的utf出现了,utf是unicode的一种实现,只不过更聪明了。utf16是占用两字节,或者四字节,utf32是占用四字节。utf8是很聪明的一种表示方式。
1、对于单字节符号,字节第一位为0,后面7位表示字节编码。
2、对于n字节符号,第一字节的前n位都设为1,第n+1位为0,其余位位编码位置。
对于不同的编码,在文本的最前方有不同的标志,unicode 通常有两位来表示分别是ff fe, 或者feff, fffe表示big-endian 编码feff表示litte-endian编码。utf8是efbbbf来开头的。可以看出来utf-8是自解释的,所以不用带这个标志文件,大多数程序是可以识别的。但有些程序不能识别这个标志,比如php就会直接把这个标志当文本解析,不会忽略。相信很多遇到php输出文本解析乱码或者解析错误的同学都遇到这样的问题。
最后说说如何去掉或者加上bom,如果有vim那最好不过了,去掉命令:
set encoding=utf-8
set nobomb
添加命令:
set encoding=utf-8
set bomb
---------------------------------------------------------
带 BOM 的 UTF-8 就是赤裸裸的流氓!!!!!!!!!
windows总是自做聪明的做一些别人无法理解的事情!!!UTF-8是不需要BOM头的~~~!!
从刚开始学习代码(实在不能称我做的东西为程序)到现在,不晓得被这个BOM头搞了多少次,特别是对于我这种完全自学的人,知道找一个BUG需要多久多久不????
带不带BOM头区别就在于这个BOM头,祥见排名靠前的大神答案。windows特有的奇葩。请使用UTF-8 不带BOM头!!
它产生的BUG包含但不仅限于:
锘 -- 感谢 @飞扬 提供,参考其答案
HTML空白行
div之间莫明的间隔
乱码!
如果你用ssl那么一定会有问题!!!
顺便再鄙视一下 SONY的记忆棒、IPHONE的接口~~
这种吐槽的东西就让它折叠吧
--------------------------------------------------------
带 BOM 的 UTF-8 非常操蛋,经常造成莫名其妙的问题。
---------------------------------------------------------
我都是用的UTF-8 without BOM,带BOM的经常出现乱码
---------------------------------------------------------
notepad++会自动添加为带Bom的utf8比较坑爹
---------------------------------------------------------
建议编程人员能使用 Mac 编程的尽量使用Mac,Window是及其操蛋的操作系统。其次,如果我们要读取三方的文件并以UTF-8格式解析的时候一定要注意去判断这个文件是否有BOM,例如:sql文件的解析执行。
---------------------------------------------------------
网页编程中用不用bom我就不说什么了,因为软件原因无法使用的就更不能用了。
最近在学习用cocos2d-x,纯C++的编码,如果代码中有中文等的非ascii字符出现。发现会出错。代码是在mac 下用xcode 写的,放到windows 下用vs 编译。
最后把所有的源文件转成了带bom的格式后编译通过了,链接失败,这想这个就不是编码的问题了。
通常情况下,一般都 会认为在写C++代码的时候不要用中文,但是很多时候我们程序员也有想自己看着舒服的时候,为神马就不能写中文了?
于是在windows 下写了一个helloworld.cpp 类型的文件,输出内容用中文,然后存为utf-8 带bom格式,再把它copy到mac 下用g++ 编译,发现成功通过并且可正常运行,用xcode打开源文件也正常显示。
所以,这里建议程序要在windows 和 mac 还有linux 上运行的话,源代码最好保存成utf-8 带bom的格式,这样比较通用一些。而用utf-16 无论大端还是小端,g++ 都不认的。或者用utf-8 不带bom格式,然后代码不要出现非ascii 127以后的字符。
关于说utf-8 不带bom 才是标准的,我想应该是带用个人情绪的说法吧。真正的标准应该是bom是可选的,为什么可选?因为有些时候不带bom会出错,就拿历史较久远的windows来讲吧,很多国家的用户都在用windows ,其文件都是用其本地的ansi 编码来做的,比如大陆的GBK和GB2013,港台的big5,这些编码因为针对当地所用的字符制定的,所以呢,其存储文件较小,所以会大量使用,并且也大量存在着,微软不可能不考虑全球几十亿的用户的文件而盲目地修改解码方式,并且微软也是uncode 制定者之一,所以,带用bom的utf-8也是符合国际标准的。
或许是因为程序编写者的个人原因,也许是考虑到效率,很多的程序无法正确区分一个utf-8文件是否有bom,所以导致了各种乱码的出现。
个人不想说哪个是标准,也不想用语言去攻击哪个公司或团体。微软在坚持使用bom上没有错,因为这是在为用户考虑的。也许给我们这些写程序的带来了不便,但是,计算机最广泛的用户不是程序员。
---------------------------------------------------------
如果觉得文章不错,可以给小编发个红包给予鼓励.