天天看點

UTF-8與UTF-8(BOM)差別和一些說明寫在前面

寫在前面

在我們通常使用的windows系統中,我發現了一個有趣的現象。我建立一個空的文本文檔,點選檔案-另存為-編碼選擇UTF-8,然後儲存。此時這個檔案明明是空的,卻占了3位元組大小。原因在于:此時儲存的編碼方式自動會變為UTF-8 BOM

一、一個漢字在不同的編碼方式中占多少位元組?

       1.在UTF-8中,一個漢字占3個位元組(一個字元占一個位元組)

      2.在ASCII碼中,一個漢字占2個位元組(一個字元占一個位元組)

      3.在Unicode編碼中,一個漢字占2個位元組(一個字元同樣占兩個位元組,是以JAVA中char a = '中';是可以的)

二、UTF-8與UTF-8 BOM

        BOM即byte order mark,具體含義可百度百科或維基百科,UTF-8檔案中放置BOM主要是微軟的習慣,但是放在别的系統上會出現問題。不含BOM的UTF-8才是标準形式,UTF-8不需要BOM帶BOM的UTF-8檔案的開頭會有U+FEFF,是以我建立的空檔案會有3位元組的大小。

BOM的含義

  BOM即Byte Order Mark位元組序标記。BOM是為UTF-16和UTF-32準備的,使用者标記位元組序(byte order)。拿UTF-16來舉例,其是以兩個位元組為編碼單元,在解釋一個UTF-16文本前,首先要弄清楚每個編碼單元的位元組序。例如收到一個“奎”的Unicode編碼是594E,“乙”的Unicode編碼是4E59。如果我們收到UTF-16位元組流"594E",那麼這是“奎”還是“乙”?

  Unicode規範中推薦的标記位元組順序的方法是BOM:在UCS編碼中有一個叫做"ZERO WIDTH NO-BREAK SPACE"(零寬度無間斷空間)的字元,它的編碼是FEFF。而FEFF在UCS中是不不能再的字元(即不可見),是以不應該出現在實際傳輸中。UCS規範建議我們在傳輸位元組流前,先傳輸字元"ZERO WIDTH NO-BREAK SPACE"。這樣如果接收者接收到FEFF,就表明這個位元組流是Big-Endian的;如果收到FFFE,就表明這個位元組流是Little-Endian的。是以字元"ZERO WIDTH NO-BREAK SPACE"又被稱為BOM。

  UTF-8是以位元組為編碼單元,沒有位元組序的問題。

延伸一下:

  UTF-8編碼是以1個位元組為機關進行處理的,不會受CPU大小端的影響;需要考慮下一位時就位址 + 1。

  UTF-16、UTF-32是以2個位元組和4個位元組為機關進行處理的,即1次讀取2個位元組或4個位元組,這樣一來,在存儲和網絡傳輸時就要考慮1個機關内2個位元組或4個位元組之間順序的問題。

UTF-8 BOM

  UTF-8 BOM又叫UTF-8 簽名,UTF-8不需要BOM來表明位元組順序,但可以用BOM來表明編碼方式。當文本程式讀取到以 EF BB BF開頭的位元組流時,就知道這是UTF-8編碼了。Windows就是使用BOM來标記文本檔案的編碼方式的。

補充:

"ZERO WIDTH NO-BREAK SPACE"字元的UCS編碼為FEFF(假設為大端),對應的UTF-8編碼為 EF BB BF 

  即以EF BB BF開頭的位元組流可表明這是段UTF-8編碼的位元組流。但如果檔案本身就是UTF-8編碼的,EF BB BF這三個位元組就毫無用處了。 是以,可以說BOM的存在對于UTF-8本身沒有任何作用。

UTF-8檔案中包含BOM的壞處

  1、對php的影響

  php在設計時就沒有考慮BOM的問題,也就是說他不會忽略UTF-8編碼的檔案開頭的那三個EF BB BF字元,直接當做文本進行解析,導緻解析錯誤。

  2、在linux上執行SQL腳本報錯

  最近開發過程中遇到,windows下編寫的SQL檔案,在linux下執行時,總是報錯。

  在檔案的開頭,無論是使用中文注釋還是英文注釋,甚至去掉注釋,也會報

SP2-0734: unknown command beginning "?<span "="">dec<span "="">lare ..." - rest of line ignored. 

的錯誤。

<span "="">

如下是檔案開頭部分

1 --create tablespace
2 declare
3 v_tbs_name varchar2(200):='hytpdtsmsshistorydb';
4 begin      

  報錯如下:

1 SP2-0734: unknown command beginning "?--create ..." - rest of line ignored.
2 
3 
4 PL/SQL procedure successfully completed.      

  網上沒有找到類似問題的解決辦法,且檔案編碼确認已經更改為utf-8,該問題困惑了我很久。

  最後檢視一下BOM與 no BOM的差別,嘗試更改為no BOM,居然就沒有再出現錯誤。

  修改完成後,無論使用中文,還是英文,或者去掉注釋,都能正常執行。

血淚建議:UTF-8最好不要帶BOM

  UTF-8」和「帶 BOM 的 UTF-8」的差別就是有沒有 BOM。即檔案開頭有沒有 U+FEFF。

  1、Linux中檢視BOM的方法:使用less指令,其它指令可能看不到效果:

UTF-8與UTF-8(BOM)差別和一些說明寫在前面

  發現詞語之前多了一個<U+FEFF>。

三、建立UTF-8(而非UTF-8 BOM)檔案的方法

        在發現檔案另存為UTF-8缺得到UTF-8 BOM檔案後,我們怎樣才能得到UTF-8呢?

方法:.先另存為UTF-8儲存,再使用notepad++打開,把裡面的編碼設定為無BOM的UTF-8然後儲存。(此方法治标不治本,因為當你再次在裡面寫漢字時,檔案會自動變成UTF-8 BOM)

UTF-8與UTF-8(BOM)差別和一些說明寫在前面

2、UTF-8去除BOM的方法

  Linux下:

  (1)

    1)vim打開檔案

    2)執行:set nobomb

    3)儲存:wq

  (2)

    dos2unix filename

    将windows格式檔案轉為Unix、Linux格式檔案。該指令不僅可将windows檔案的換行符\r\n轉為Unix、Linux檔案的換行符\n,還可以将UTF-8 Unicode (with BOM)轉換為UTF-8 Unicode.

  PS:

  遇到一個比較坑爹的情況,1個UTF-8 Unicode (with BOM)檔案中包含兩個<U+FEFF>,這是無論使用方法(1)還是方法(2),都要執行兩次才能将<U+FEFF>完全去除!!!

  (2)Windows下,使用NotePad++打開這個檔案,然後選擇“編碼”,再選擇“以UTF-8無BOM格式編碼”,最後重新儲存檔案即可!

寫在前面

在我們通常使用的windows系統中,我發現了一個有趣的現象。我建立一個空的文本文檔,點選檔案-另存為-編碼選擇UTF-8,然後儲存。此時這個檔案明明是空的,卻占了3位元組大小。原因在于:此時儲存的編碼方式自動會變為UTF-8 BOM

一、一個漢字在不同的編碼方式中占多少位元組?

       1.在UTF-8中,一個漢字占3個位元組(一個字元占一個位元組)

      2.在ASCII碼中,一個漢字占2個位元組(一個字元占一個位元組)

      3.在Unicode編碼中,一個漢字占2個位元組(一個字元同樣占兩個位元組,是以JAVA中char a = '中';是可以的)

二、UTF-8與UTF-8 BOM

        BOM即byte order mark,具體含義可百度百科或維基百科,UTF-8檔案中放置BOM主要是微軟的習慣,但是放在别的系統上會出現問題。不含BOM的UTF-8才是标準形式,UTF-8不需要BOM帶BOM的UTF-8檔案的開頭會有U+FEFF,是以我建立的空檔案會有3位元組的大小。

BOM的含義

  BOM即Byte Order Mark位元組序标記。BOM是為UTF-16和UTF-32準備的,使用者标記位元組序(byte order)。拿UTF-16來舉例,其是以兩個位元組為編碼單元,在解釋一個UTF-16文本前,首先要弄清楚每個編碼單元的位元組序。例如收到一個“奎”的Unicode編碼是594E,“乙”的Unicode編碼是4E59。如果我們收到UTF-16位元組流"594E",那麼這是“奎”還是“乙”?

  Unicode規範中推薦的标記位元組順序的方法是BOM:在UCS編碼中有一個叫做"ZERO WIDTH NO-BREAK SPACE"(零寬度無間斷空間)的字元,它的編碼是FEFF。而FEFF在UCS中是不不能再的字元(即不可見),是以不應該出現在實際傳輸中。UCS規範建議我們在傳輸位元組流前,先傳輸字元"ZERO WIDTH NO-BREAK SPACE"。這樣如果接收者接收到FEFF,就表明這個位元組流是Big-Endian的;如果收到FFFE,就表明這個位元組流是Little-Endian的。是以字元"ZERO WIDTH NO-BREAK SPACE"又被稱為BOM。

  UTF-8是以位元組為編碼單元,沒有位元組序的問題。

延伸一下:

  UTF-8編碼是以1個位元組為機關進行處理的,不會受CPU大小端的影響;需要考慮下一位時就位址 + 1。

  UTF-16、UTF-32是以2個位元組和4個位元組為機關進行處理的,即1次讀取2個位元組或4個位元組,這樣一來,在存儲和網絡傳輸時就要考慮1個機關内2個位元組或4個位元組之間順序的問題。

UTF-8 BOM

  UTF-8 BOM又叫UTF-8 簽名,UTF-8不需要BOM來表明位元組順序,但可以用BOM來表明編碼方式。當文本程式讀取到以 EF BB BF開頭的位元組流時,就知道這是UTF-8編碼了。Windows就是使用BOM來标記文本檔案的編碼方式的。

補充:

"ZERO WIDTH NO-BREAK SPACE"字元的UCS編碼為FEFF(假設為大端),對應的UTF-8編碼為 EF BB BF 

  即以EF BB BF開頭的位元組流可表明這是段UTF-8編碼的位元組流。但如果檔案本身就是UTF-8編碼的,EF BB BF這三個位元組就毫無用處了。 是以,可以說BOM的存在對于UTF-8本身沒有任何作用。

UTF-8檔案中包含BOM的壞處

  1、對php的影響

  php在設計時就沒有考慮BOM的問題,也就是說他不會忽略UTF-8編碼的檔案開頭的那三個EF BB BF字元,直接當做文本進行解析,導緻解析錯誤。

  2、在linux上執行SQL腳本報錯

  最近開發過程中遇到,windows下編寫的SQL檔案,在linux下執行時,總是報錯。

  在檔案的開頭,無論是使用中文注釋還是英文注釋,甚至去掉注釋,也會報

SP2-0734: unknown command beginning "?<span "="">dec<span "="">lare ..." - rest of line ignored. 

的錯誤。

<span "="">

如下是檔案開頭部分

1 --create tablespace
2 declare
3 v_tbs_name varchar2(200):='hytpdtsmsshistorydb';
4 begin      

  報錯如下:

1 SP2-0734: unknown command beginning "?--create ..." - rest of line ignored.
2 
3 
4 PL/SQL procedure successfully completed.      

  網上沒有找到類似問題的解決辦法,且檔案編碼确認已經更改為utf-8,該問題困惑了我很久。

  最後檢視一下BOM與 no BOM的差別,嘗試更改為no BOM,居然就沒有再出現錯誤。

  修改完成後,無論使用中文,還是英文,或者去掉注釋,都能正常執行。

血淚建議:UTF-8最好不要帶BOM

  UTF-8」和「帶 BOM 的 UTF-8」的差別就是有沒有 BOM。即檔案開頭有沒有 U+FEFF。

  1、Linux中檢視BOM的方法:使用less指令,其它指令可能看不到效果:

繼續閱讀