UTF8 與 UTF8 +BOM 區別

一個帶標籤,一個沒有標籤。
BOM是Byte Order Mark(定義字節順序),由於在網絡傳輸中分兩種順序:大頭和小頭。php

因爲兼容性,帶BOM的utf-8在一些browser中顯示爲亂碼。html

網上搜索了關於Byte Order Mark的信息:
在UCS 編碼中有一個叫作"ZERO WIDTH NO-BREAK SPACE"的字符,它的編碼是FEFF。而FFFE在UCS中是不存在的字符,因此不該該出如今實際傳輸中。UCS規範建python

議咱們在傳輸字節流前,先傳輸字符"ZERO WIDTH NO-BREAK SPACE"。這樣若是接收者收到FEFF,就代表這個字節流是Big-Endian的;若是收到FFFE,就代表這程序員

個字節流是Little- Endian的。所以字符"ZERO WIDTH NO-BREAK SPACE"又被稱做BOM。
UTF-8不須要BOM來代表字節順序,但能夠用BOM來代表編碼方式。字符"ZERO WIDTH NO-BREAK SPACE"的UTF-8編碼是EF BB BF。因此若是接收者收到以EF BB BF算法

開頭的字節流,就知道這是UTF-8編碼了。
Windows就是使用BOM來標記文本文件的編碼方式的。shell

帶BOM的UTF-8,全部PHP沒法識別,直接將EF BB BF輸出,在charset="utf-8"的頁面中是空白,在GB2312的頁面中的輸出的就是稀有漢字:鍩匡豢vim

 

怎麼轉化爲 UTF-8,無bom格式 ??
用 UltarEdit   能夠轉化的
直接用UE打開你的文件,而後在文件選項裏面有一個轉化的選項
裏面選ascii轉化爲 uft-8 就能夠了網絡

【UTF8 + BOM產生問題與小結】
寫python腳本的時候發現這樣一個問題:從xls文件導出到txt時,沒法直接轉換爲int型數據,輸出查看發現和文件編碼方式產生的附加信息有關用一個簡單的編輯器

文件舉例測試

90905

90907

90908

90909

90939

90940

90946

90959

90961

90965

當文件分別用ascii,utf8,utf8+bom做爲編碼格式時,顯示輸出結果以下:

使用ascii編碼的輸出:

['90905\r\n', '90907\r\n', '90908\r\n', '90909\r\n', '90939\r\n', '90940\r\n', '90946\r\n', '90959\r\n', '90961\r\n', '90965']

使用utf8編碼的輸出:

['90905\r\n', '90907\r\n', '90908\r\n', '90909\r\n', '90939\r\n', '90940\r\n', '90946\r\n', '90959\r\n', '90961\r\n', '90965']

使用bom編碼的輸出:

['\xef\xbb\xbf90905\r\n', '90907\r\n', '90908\r\n', '90909\r\n', '90939\r\n', '90940\r\n', '90946\r\n', '90959\r\n', '90961\r\n', '90965']

原來utf8+bom不能直接轉換int的緣由在這裏,它在文件頭插入了一個表示文件編碼的信息\xef\xbb\xbf,那麼UTF-8(無BOM)和UTF-8這兩個有什麼區別呢?

BOM是什麼呢?

什麼是BOM?
BOM: Byte Order Mark
UTF-8 BOM又叫UTF-8 簽名,其實UTF-8 的BOM對UFT-8沒有做用,是爲了支持UTF-16,UTF-32才加上的

BOM,BOM簽名的意思就是告訴編輯器當前文件採用何種編碼,方便編輯器識別,可是BOM雖然在編輯器中不顯示,可是會產生輸出,就像多了一個空行。

Byte Order Marks are special characters at the beginning of a Unicode file to indicate whether it is big or little endian, in other words

does the high or low order byte come first. These codes also tell whether the encoding is 8, 16 or 32 bit. You can recognise Unicode files by their starting byte order marks, and by the way Unicode-16 files are half zeroes and Unicode-32 files are three-quarters zeros. Unicode Endian Markers

Byte-order mark Description
EF BB BF UTF-8
FF FE UTF-16 aka UCS-2, little endian
FE FF UTF-16 aka UCS-2, big endian
00 00 FF FE UTF-32 aka UCS-4, little endian.
00 00 FE FF UTF-32 aka UCS-4, big-endian.

UTF的字節序和BOM
UTF- 8以字節爲編碼單元,沒有字節序的問題。UTF-16以兩個字節爲編碼單元,在解釋一個UTF-16文本前,首先要弄清楚每一個編碼單元的字節序。例如收到 一個「奎」的Unicode編碼是594E,「乙」的Unicode編碼是4E59。若是咱們收到UTF-16字節流「594E」,那麼這是「奎」仍是 「乙」?

Unicode規範中推薦的標記字節順序的方法是BOM。BOM不是「Bill Of Material」的BOM表,而是Byte Order Mark。BOM是一個有點小聰明的想法:

在 UCS編碼中有一個叫作"ZERO WIDTH NO-BREAK SPACE"的字符,它的編碼是FEFF。而FFFE在UCS中是不存在的字符,因此不該該出如今實際傳輸中。UCS規範建議咱們在傳輸字節流前,先傳輸 字符"ZERO WIDTH NO-BREAK SPACE"。

這樣若是接收者收到FEFF,就代表這個字節流是Big-Endian的;若是收到FFFE,就代表這個字節流是Little-Endian的。所以字符"ZERO WIDTH NO-BREAK SPACE"又被稱做BOM。

UTF-8不須要BOM來代表字節順序,但能夠用BOM來代表編碼方式。字符"ZERO WIDTH NO-BREAK SPACE"的UTF-8編碼是EF BB BF。因此若是接收者收到以EF BB BF開頭的字節流,就知道這是UTF-8編碼了。

Windows就是使用BOM來標記文本文件的編碼方式的。

原來BOM是在文件的開始加了幾個字節做爲標記。有了這個標記,一些協議和系統才能識別。

ok,說了這麼多背景,那麼如何解決這個問題呢?

如何使用BOM頭
BOM頭的刪除
對UTF-16, Python將BOM解碼爲空字串。然而對UTF-8, BOM被解碼爲一個字符,如例:

>>> codecs.BOM_UTF16.decode( "utf16" )  u''  >>> codecs.BOM_UTF8.decode( "utf8" )  u'\ufeff'簡單的作法是在文件讀入時使用

import codecs

f = codecs.open(sys.argv[1],'r', 'utf_8_sig')便可,具體能夠參見[http://docs.python.org/library/codecs.html#module-

encodings.utf_8_sig|http://docs.python.org/library/codecs.html#module-encodings.utf_8_sig]

或者:

u.lstrip( unicode( codecs.BOM_UTF8, "utf8" ) )BOM頭的添加
out = file( "someFile", "w" )
out.write( codecs.BOM_UTF8 )
out.write( unicodeString.encode( "utf-8" ) )
out.close()out = file( "someFile", "w" )out.write( codecs.BOM_UTF8 )out.write( unicodeString.encode( "utf-8" ) )out.close()詳細的過程解釋可

以參見[http://mindprod.com/jgloss/encoding.html|http://mindprod.com/jgloss/encoding.html]

參考資料:

[http://blog.sina.com.cn/s/blog_3e9d2b350100as0b.html|http://blog.sina.com.cn/s/blog_3e9d2b350100as0b.html]

[http://4nail.iteye.com/blog/840612|http://4nail.iteye.com/blog/840612]

【UTF8和UTF8 + BOM 網頁代碼通常使用哪一個?】

首先,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用這個有歷史緣由,由於它最初脫胎於多代碼頁的環 境。而引入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.: 爲何說VIM去除bomb的操做須要在UNIX下完成。由於VIM在Windows環境下有一個奇怪的bug,老是把UTF-16文件識別成二進制文 件,而UNIX(Linux或者Mac均可以)下VIM則無問題。這個問題從VIM 6.8一直跟着我到VIM 7.3。目前尚不清楚這是VIM的bug仍是我本身那個.vimrc文件的bug。


【談談Unicode編碼,簡要解釋UCS、UTF、BMP、BOM等名詞】
這是一篇程序員寫給程序員的趣味讀物。所謂趣味是指能夠比較輕鬆地瞭解一些原來不清楚的概念,增進知識,相似於打RPG遊戲的升級。整理這篇文章的動機是兩個問題:

問題一:
使用Windows記事本的「另存爲」,能夠在GBK、Unicode、Unicode big endian和UTF-8這幾種編碼方式間相互轉換。一樣是txt文件,Windows是怎樣識別編碼方式的呢?

我 很早前就發現Unicode、Unicode big endian和UTF-8編碼的txt文件的開頭會多出幾個字節,分別是FF、FE(Unicode),FE、FF(Unicode big endian),EF、BB、BF(UTF-8)。但這些標記是基於什麼標準呢?

問題二:
最近在網上看到一個 ConvertUTF.c,實現了UTF-3二、UTF-16和UTF-8這三種編碼方式的相互轉換。對於Unicode(UCS2)、GBK、UTF- 8這些編碼方式,我原來就瞭解。但這個程序讓我有些糊塗,想不起來UTF-16和UCS2有什麼關係。
查了查相關資料,總算將這些問題弄清楚了,順帶也瞭解了一些Unicode的細節。寫成一篇文章,送給有過相似疑問的朋友。本文在寫做時儘可能作到通俗易懂,但要求讀者知道什麼是字節,什麼是十六進制。

0、big endian和little endian
big endian和little endian是CPU處理多字節數的不一樣方式。例如「漢」字的Unicode編碼是6C49。那麼寫到文件裏時,到底是將6C寫在前面,仍是將49寫在前 面?若是將6C寫在前面,就是big endian。仍是將49寫在前面,就是little endian。

「endian」這個詞出自《格列佛遊記》。小人國的內戰就源於吃雞蛋時是究竟從大頭(Big-Endian)敲開仍是從小頭(Little-Endian)敲開,由此曾發生過六次叛亂,其中一個皇帝送了命,另外一個丟了王位。

咱們通常將endian翻譯成「字節序」,將big endian和little endian稱做「大尾」和「小尾」。

一、字符編碼、內碼,順帶介紹漢字編碼
字符必須編碼後才能被計算機處理。計算機使用的缺省編碼方式就是計算機的內碼。早期的計算機使用7位的ASCII編碼,爲了處理漢字,程序員設計了用於簡體中文的GB2312和用於繁體中文的big5。

GB2312(1980年)一共收錄了7445個字符,包括6763個漢字和682個其它符號。漢字區的內碼範圍高字節從B0-F7,低字節從A1-FE,佔用的碼位是72*94=6768。其中有5個空位是D7FA-D7FE。

GB2312支持的漢字太少。1995年的漢字擴展規範GBK1.0收錄了21886個符號,它分爲漢字區和圖形符號區。漢字區包括21003個字符。2000年的GB18030是取代

GBK1.0的正式國家標準。該標準收錄了27484個漢字,同時還收錄了藏文、蒙文、維吾爾文等主要的少數民族文字。如今的PC平臺必須支持GB18030,對嵌入式產品暫不做要求。因此手機、MP3通常只支持GB2312。

從 ASCII、GB23十二、GBK到GB18030,這些編碼方法是向下兼容的,即同一個字符在這些方案中老是有相同的編碼,後面的標準支持更多的字符。 在這些編碼中,英文和中文能夠統一地處理。區分中文編碼的方法是高字節的最高位不爲0。按照程序員的稱呼,GB23十二、GBK到GB18030都屬於雙 字節字符集 (DBCS)。

有的中文Windows的缺省內碼仍是GBK,能夠經過GB18030升級包升級到GB18030。不過GB18030相對GBK增長的字符,普通人是很難用到的,一般咱們仍是用GBK指代中文Windows內碼。

這裏還有一些細節:

GB2312的原文仍是區位碼,從區位碼到內碼,須要在高字節和低字節上分別加上A0。

在DBCS中,GB內碼的存儲格式始終是big endian,即高位在前。

GB2312的兩個字節的最高位都是1。但符合這個條件的碼位只有128*128=16384個。因此GBK和GB18030的低字節最高位均可能不是1。不過這不影響DBCS字符流的

解析:在讀取DBCS字符流時,只要遇到高位爲1的字節,就能夠將下兩個字節做爲一個雙字節編碼,而不用管低字節的高位是什麼。

二、 Unicode、UCS和UTF 前面提到從ASCII、GB23十二、GBK到GB18030的編碼方法是向下兼容的。而Unicode只與ASCII兼容(更準確地說,是與ISO- 8859-1兼容),與GB碼不兼容。例如「漢」字的Unicode編碼是6C49,而GB碼是BABA。

Unicode也是一種字 符編碼方法,不過它是由國際組織設計,能夠容納全世界全部語言文字的編碼方案。Unicode的學名是"Universal Multiple-Octet Coded Character Set",簡稱爲UCS。UCS能夠看做是"Unicode Character Set"的縮寫。

根據維基百科全書(http://zh.wikipedia.org/wiki/)的記載:歷史上存在兩個試圖獨立 設計Unicode的組織,即國際標準化組織(ISO)和一個軟件製造商的協會(unicode.org)。ISO開發了ISO 10646項目,Unicode協會開發了Unicode項目。

在1991年先後,雙方都認識到世界不須要兩個不兼容的字符集。因而它們開始合併雙方的工做成果,併爲創立一個單一編碼表而協同工做。從Unicode2.0開始,Unicode項目採用了與ISO 10646-1相同的字庫和字碼。

目前兩個項目仍都存在,並獨立地公佈各自的標準。Unicode協會如今的最新版本是2005年的Unicode 4.1.0。ISO的最新標準是10646-3:2003。

UCS規定了怎麼用多個字節表示各類文字。怎樣傳輸這些編碼,是由UTF(UCS Transformation Format)規範規定的,常見的UTF規範包括UTF-八、UTF-七、UTF-16。

IETF 的RFC2781和RFC3629以RFC的一向風格,清晰、明快又不失嚴謹地描述了UTF-16和UTF-8的編碼方法。我老是記不得IETF是 Internet Engineering Task Force的縮寫。但IETF負責維護的RFC是Internet上一切規範的基礎。

三、UCS-二、UCS-四、BMP UCS有兩種格式:UCS-2和UCS-4。顧名思義,UCS-2就是用兩個字節編碼,UCS-4就是用4個字節(實際上只用了31位,最高位必須爲0)編碼。下面讓咱們作一些簡單的數學遊戲:

UCS-2有2^16=65536個碼位,UCS-4有2^31=2147483648個碼位。

UCS- 4根據最高位爲0的最高字節分紅2^7=128個group。每一個group再根據次高字節分爲256個plane。每一個plane根據第3個字節分爲 256行 (rows),每行包含256個cells。固然同一行的cells只是最後一個字節不一樣,其他都相同。

group 0的plane 0被稱做Basic Multilingual Plane, 即BMP。或者說UCS-4中,高兩個字節爲0的碼位被稱做BMP。

將UCS-4的BMP去掉前面的兩個零字節就獲得了UCS-2。在UCS-2的兩個字節前加上兩個零字節,就獲得了UCS-4的BMP。而目前的UCS-4規範中尚未任何字符被分配在BMP以外。

四、UTF編碼

UTF-8就是以8位爲單元對UCS進行編碼。從UCS-2到UTF-8的編碼方式以下:

UCS-2編碼(16進制) UTF-8 字節流(二進制)
0000 - 007F 0xxxxxxx
0080 - 07FF 110xxxxx 10xxxxxx
0800 - FFFF 1110xxxx 10xxxxxx 10xxxxxx

例 如「漢」字的Unicode編碼是6C49。6C49在0800-FFFF之間,因此確定要用3字節模板了:1110xxxx 10xxxxxx 10xxxxxx。將6C49寫成二進制是:0110 110001 001001, 用這個比特流依次代替模板中的x,獲得:11100110 10110001 10001001,即E6 B1 89。

讀者能夠用記事本測試一下咱們的編碼是否正確。

UTF- 16以16位爲單元對UCS進行編碼。對於小於0x10000的UCS碼,UTF-16編碼就等於UCS碼對應的16位無符號整數。對於不小於 0x10000的UCS碼,定義了一個算法。不過因爲實際使用的UCS2,或者UCS4的BMP必然小於0x10000,因此就目前而言,能夠認爲 UTF-16和UCS-2基本相同。但UCS-2只是一個編碼方案,UTF-16卻要用於實際的傳輸,因此就不得不考慮字節序的問題。

五、UTF的字節序和BOM
UTF- 8以字節爲編碼單元,沒有字節序的問題。UTF-16以兩個字節爲編碼單元,在解釋一個UTF-16文本前,首先要弄清楚每一個編碼單元的字節序。例如收到 一個「奎」的Unicode編碼是594E,「乙」的Unicode編碼是4E59。若是咱們收到UTF-16字節流「594E」,那麼這是「奎」仍是 「乙」?

Unicode規範中推薦的標記字節順序的方法是BOM。BOM不是「Bill Of Material」的BOM表,而是Byte Order Mark。BOM是一個有點小聰明的想法:

在 UCS編碼中有一個叫作"ZERO WIDTH NO-BREAK SPACE"的字符,它的編碼是FEFF。而FFFE在UCS中是不存在的字符,因此不該該出如今實際傳輸中。UCS規範建議咱們在傳輸字節流前,先傳輸 字符"ZERO WIDTH NO-BREAK SPACE"。 這樣若是接收者收到FEFF,就代表這個字節流是Big-Endian的;若是收到FFFE,就代表這個字節流是Little-Endian的。所以字 符"ZERO WIDTH NO-BREAK SPACE"又被稱做BOM。

UTF-8不須要BOM來代表字節順序,但能夠用BOM 來代表編碼方式。字符"ZERO WIDTH NO-BREAK SPACE"的UTF-8編碼是EF BB BF(讀者能夠用咱們前面介紹的編碼方法驗證一下)。因此若是接收者收到以EF BB BF開頭的字節流,就知道這是UTF-8編碼了。

Windows就是使用BOM來標記文本文件的編碼方式的。

六、進一步的參考資料
本文主要參考的資料是 "Short overview of ISO-IEC 10646 and Unicode" (http://www.nada.kth.se/i18n/ucs/unicode-iso10646-oview.html)。

兩篇看上去不錯的資料:

"Understanding Unicode A general introduction to the Unicode Standard" (http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&item_id=IWS-Chapter04a) "Character set encoding basics Understanding character set encodings and legacy encodings" (http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&item_id=IWS-Chapter03) 網上應該有UTF-八、UCS-二、GBK相互轉換的軟件包,包括使用Windows API和不使用Windows API的版本。

相關文章
相關標籤/搜索