UTF-8

dead-url=no 2008年，UTF-8的使用率超過所有其他編碼方式，在2012年超過所有網頁的60％。其中ASCII only曲線包括所有僅包含ASCII字符的網頁，無論元數據中聲明如何。
UTF-8（8-bit Unicode Transformation Format）是一種針對Unicode的可變長度字元編碼，也是一種前綴碼。它可以用一至四個字節對Unicode字符集中的所有有效編碼點進行編碼，屬於Unicode標準的一部分，最初由肯·湯普遜和羅布·派克提出。由於較小值的編碼點一般使用頻率較高，直接使用Unicode編碼效率低下，大量浪費內存空間。UTF-8就是為了解決向後兼容ASCII碼而設計，Unicode中前128個字符，使用與ASCII碼相同的二進制值的單個字節進行編碼，而且字面與ASCII碼的字面一一對應，這使得原來處理ASCII字元的軟體無須或只須做少部份修改，即可繼續使用。因此，它逐漸成為電子郵件、網頁及其他儲存或傳送文字優先採用的編碼方式。
自2009年以來，UTF-8一直是萬維網的最主要的編碼形式（對所有，而不僅是Unicode範圍內的編碼）（並由WHATWG宣佈為強制性的“適用於所有事物(for all things)”，截止到2019年11月， 在所有網頁中，UTF-8編碼應用率高達94.3%（其中一些僅是ASCII編碼，因為它是UTF-8的子集），而在排名最高的1000個網頁中佔96％。 第二熱門的多字節編碼方式Shift JIS和GB 2312分別具有0.3％和0.2％的佔有率。Internet郵件聯盟（ Internet Mail Consortium, IMC）建議所有電子郵件程序都能夠使用UTF-8展示和創建郵件， W3C建議UTF-8作為XML文件和HTML文件的默認編碼方式。網際網路工程工作小組（IETF）要求所有網際網路協議都必須支持UTF-8編碼。互聯網郵件聯盟（IMC）建議所有電子郵件軟件都支持UTF-8編碼。

**歷史**
1992年初，為建立良好的位元組串編碼系統以供多位元組字元集使用，開始了一個正式的研究。ISO/IEC 10646的初稿中有一個非必須的附錄，名為UTF。當中包含了一個供32位元的字元使用的位元組串編碼系統。這個編碼方式的性能並不令人滿意，但它提出了將0-127的範圍保留給ASCII以相容舊系統的概念。
1992年7月，X/Open委員會XoJIG開始尋求一個較佳的編碼系統。Unix系統實驗室（USL）的Dave Prosser為此提出了一個編碼系統的建議。它具備可更快速實作的特性，並引入一項新的改進。其中，7位元的ASCII符號只代表原來的意思，所有多位元組序列則會包含第8位元的符號，也就是所謂的最高有效位元。
1992年8月，這個建議由IBMX/Open的代表流傳到一些感興趣的團體。與此同時，貝爾實驗室九號計畫作業系統工作小組的肯·湯普遜對這編碼系統作出重大的修改，讓編碼可以自我同步，使得不必從字串的開首讀取，也能找出字符間的分界。1992年9月2日，肯·湯普遜和羅勃·派克一起在美國新澤西州一架餐車的餐桌墊上描繪出此設計的要點。接下來的日子，Pike及湯普遜將它實現，並將這編碼系統完全應用在九號計畫當中，及後他將有關成果回饋X/Open。
1993年1月25-29日的在聖地牙哥舉行的USENIX會議首次正式介紹UTF-8。
自1996年起，微軟的CAB（MS Cabinet）規格在UTF-8標準正式落實前就明確容許在任何地方使用UTF-8編碼系統。但有關的編碼器實際上從來沒有實作這方面的規格。

**結構**
UTF-8使用一至六個位元組為每個字符編碼（儘管如此，2003年11月UTF-8被RFC 3629重新規範，只能使用原來Unicode定義的區域，U+0000到U+10FFFF，也就是說最多四個字節）：
# 128個US-ASCII字符只需一個位元組編碼（Unicode範圍由U+0000至U+007F）。
# 帶有附加符號的拉丁文、希臘文、西里爾字母、亞美尼亞語、希伯來文、阿拉伯文、敘利亞文及它拿字母則需要兩個位元組編碼（Unicode範圍由U+0080至U+07FF）。
# 其他基本多文種平面（BMP）中的字元（這包含了大部分常用字，如大部分的漢字）使用三個位元組編碼（Unicode範圍由U+0800至U+FFFF）。
# 其他極少使用的Unicode 輔助平面的字元使用四至六位元組編碼（Unicode範圍由U+10000至U+1FFFFF使用四字節，Unicode範圍由U+200000至U+3FFFFFF使用五字節，Unicode範圍由U+4000000至U+7FFFFFFF使用六字節）。
對上述提及的第四種字元而言，UTF-8使用四至六個位元組來編碼似乎太耗費資源了。但UTF-8對所有常用的字元都可以用三個位元組表示，而且它的另一種選擇，UTF-16編碼，對前述的第四種字符同樣需要四個位元組來編碼，所以要決定UTF-8或UTF-16哪種編碼比較有效率，還要視所使用的字元的分佈範圍而定。不過，如果使用一些傳統的壓縮系統，比如DEFLATE，則這些不同編碼系統間的的差異就變得微不足道了。若顧及傳統壓縮算法在壓縮較短文字上的效果不大，可以考慮使用Unicode標準壓縮格式（SCSU）。

**描述**
Unicode與UTF-8的轉換
目前有好幾份關於UTF-8詳細規格的文件，但這些文件在定義上有些許的不同：- RFC 3629 / STD 63（2003），這份文件制定了UTF-8是標準的網際網路協議元素- 第四版，The Unicode Standard，§3.9－§3.10（2003）- ISO/IEC 10646-1:2000附加文件D（2000）
它們取代了以下那些被淘汰的定義：- ISO/IEC 10646-1:1993修正案2／附加文件R（1996）- 第二版，The Unicode Standard，附錄A（1996）- RFC 2044（1996）- RFC 2279（1998）- 第三版，The Unicode Standard，§2.3（2000）及勘誤表#1：UTF-8 Shortest Form（2000）- Unicode Standard附加文件#27: Unicode 3.1（2001）
事實上，所有定義的基本原理都是相同的，它們之間最主要的不同是支持的字元範圍及無效輸入的處理方法。
Unicode字元的位元被分割為數個部分，並分配到UTF-8的位元組串中較低的位元的位置。在U+0080的以下字元都使用內含其字元的單位元組編碼。這些編碼正好對應7位元的ASCII字符。在其他情況，有可能需要多達4個字元組來表示一個字元。這些多位元組的最高有效位元會設定成1，以防止與7位元的ASCII字符混淆，並保持標準的位元組主導字串運作順利。
Note 1 Unicode在範圍D800-DFFF中不存在任何字元，基本多文種平面中約定了這個範圍用於UTF-16擴展標識輔助平面（兩個UTF-16表示一個輔助平面字符）。當然，任何編碼都是可以被轉換到這個範圍，但在unicode中他們並不代表任何合法的值。
例如，希伯來語字母aleph（א）的Unicode代碼是U+05D0，按照以下方法改成UTF-8：- 它屬於U+0080到U+07FF區域，這個表說明它使用雙字節，110yyyyy 10zzzzzz.- 十六進制的0x05D0換算成二進制就是101-1101-0000.- 這11位數按順序放入"y"部分和"z"部分：11010111 10010000.- 最後結果就是雙字節，用十六進制寫起來就是0xD7 0x90，這就是這個字符aleph（א）的UTF-8編碼。
所以開始的128個字元（US-ASCII）只需一字節，接下來的1920個字符需要雙字節編碼，包括帶附加符號的拉丁字母，希臘字母，西裡爾字母，科普特語字母，亞美尼亞語字母，希伯來文字母和阿拉伯字母的字元。基本多文種平面中其餘的字元使用三個字節，剩餘字符使用四個字節。
根據這種方式可以處理更大數量的字元。原來的規範允許長達6字節的序列，可以覆蓋到31位元（通用字符集原來的極限）。儘管如此，2003年11月UTF-8被RFC 3629重新規範，-{只}-能使用原來Unicode定義的區域，U+0000到U+10FFFF。根據這些規範，以下字節值將無法出現在合法UTF-8序列中：

**UTF-8編碼字節含義**
對於UTF-8編碼中的任意字節B，如果B的第一位為0，則B獨立的表示一個字符(ASCII碼)；
*如果B的第一位為1，第二位為0，則B為一個多字節字符中的一個字節(非ASCII字符)；
*如果B的前兩位為1，第三位為0，則B為兩個字節表示的字符中的第一個字節；
*如果B的前三位為1，第四位為0，則B為三個字節表示的字符中的第一個字節；
*如果B的前四位為1，第五位為0，則B為四個字節表示的字符中的第一個字節；
因此，對UTF-8編碼中的任意字節，根據第一位，可判斷是否為ASCII字符；根據前二位，可判斷該字節是否為一個字符編碼的第一個字節；根據前四位（如果前兩位均為1），可確定該字節為字符編碼的第一個字節，並且可判斷對應的字符由幾個字節表示；根據前五位（如果前四位為1），可判斷編碼是否有錯誤或數據傳輸過程中是否有錯誤。

**設計UTF-8的理由**
UTF-8的設計有以下的多字元組序列的特質：
*單位元組字符的最高有效位元永遠為0。
*多位元組序列中的首個字元組的幾個最高有效位元決定了序列的長度。最高有效位為110的是2位元組序列，而1110的是三位元組序列，如此類推。
*多位元組序列中其餘的位元組中的首兩個最高有效位元為10。
UTF-8的這些特質，保證了一個字符的字節序列不會包含在另一個字符的字節序列中。這確保了以位元組為基礎的部份字串比對（sub-string match）方法可以適用於在文字中搜尋字或詞。有些比較舊的可變長度8位元編碼（如Shift JIS）沒有這個特質，故字串比對的算法變得相當複雜。雖然這增加了UTF-8編碼的字串的信息冗餘，但是利多於弊。另外，資料壓縮並非Unicode的目的，所以不可混為一談。即使在傳送過程中有部份位元組因錯誤或幹擾而完全遺失，還是有可能在下一個字符的起點重新同步，令受損範圍受到限制。
另一方面，由於其位元組序列設計，如果一個疑似為字符串的序列被驗證為UTF-8編碼，那麼我們可以有把握地說它是UTF-8字符串。一段兩位元組隨機序列碰巧為合法的UTF-8而非ASCII的機率為32分1。對於三位元組序列的機率為256分1，對更長的序列的機率就更低了。

**UTF-8的編碼方式**
UTF-8是UNICODE的一種變長度的編碼表達方式一般UNICODE為雙位元組（指UCS2），它由肯·湯普遜（Ken Thompson）於1992年建立，現在已經標準化為RFC 3629。UTF-8就是以8位為單元對UCS進行編碼，而UTF-8不使用大尾序和小尾序的形式，每個使用UTF-8儲存的字符，除了第一個字節外，其餘字節的頭兩個位元都是以"10"開始，使文字處理器能夠較快地找出每個字符的開始位置。
但為了與以前的ASCII碼相容（ASCII為一個位元組），因此UTF-8選擇了使用可變長度字節來儲存Unicode：
（注意：不論是Unicode (Table 3.7) ，還是ISO 10646 (10.2 UTF-8) ，目前都只規定了最高碼位是0x10FFFF的字元的編碼。下表中表示大於0x10FFFF的UTF-8編碼是不符合標準的。）- 在ASCII碼的範圍，用一個位元組表示，超出ASCII碼的範圍就用位元組表示，這就形成了我們上面看到的UTF-8的表示方法，這樣的好處是當UNICODE文件中-{只}-有ASCII碼時，儲存的文件都為一個位元組，所以就是普通的ASCII文件無異，讀取的時候也是如此，所以能與以前的ASCII文件相容。- 大於ASCII碼的，就會由上面的第一位元組的前幾位表示該unicode字元的長度，比如110xxxxx前三位的二進位表示告訴我們這是個2BYTE的UNICODE字元；1110xxxx是個三位的UNICODE字元，依此類推；xxx的位置由字符編碼數的二進製表示的位填入。越靠右的x具有越少的特殊意義。只用最短的那個足夠表達一個字符編碼數的多字節串。注意在多字節串中，第一個字節的開頭"1"的數目就是整個串中字節的數目。
ASCII字母繼續使用1字節儲存，重音文字、希臘字母或西里爾字母等使用2字節來儲存，而常用的漢字就要使用3字節。輔助平面字元則使用4字節。
在UTF-8+BOM格式文件的開首，很多時都放置一個U+FEFF字符（UTF-8以EF,BB,BF代表），以顯示這個文字檔案是以UTF-8編碼。

**UTF-8的特性**
 UCS字符U+0000到U+007F（ASCII）被編碼為字節0x00到0x7F（ASCII兼容），這也意味著只包含7位ASCII字符的文件在ASCII和UTF-8兩種編碼方式下是一樣的。
*所有>U+007F的UCS字符被編碼為一個多個字節的串，每個字節都有標記位集。因此，ASCII字節（0x00-0x7F）不可能作為任何其他字符的一部分。
*表示非ASCII字符的多字節串的第一個字節總是在0xC0到0xFD的範圍裡，並指出這個字符包含多少個字節。多字節串的其餘字節都在0x80到0xBF範圍裡，這使得重新同步非常容易，並使編碼無國界，且很少受丟失字節的影響。
*可以編入所有可能的231個UCS代碼- UTF-8編碼字符理論上可以最多到6個字節長，然而16位BMP字符最多隻用到3字節長。- Bigendian UCS-4字節串的排列順序是預定的。
*字節0xFE和0xFF在UTF-8編碼中從未用到，同時，UTF-8以位元組為編碼單元，它的位元組順序在所有系統中都是一様的，沒有位元組序的問題，也因此它實際上並不需要BOM。
*與UTF-16或其他Unicode編碼相比，對於不支持Unicode和XML的系統，UTF-8更不容易造成問題。

**UTF-8編碼的優點**
總體來說，在Unicode字符串中不可能由碼點數量決定顯示它所需要的長度，或者顯示字符串之後在文本緩衝區中光標應該放置的位置；組合字符、變寬字體、不可打印字符和從右至左的文字都是其歸因。
所以儘管在UTF-8字符串中字元數量與碼點數量的關係比UTF-32更為複雜，在實際中很少會遇到有不同的情形。
更詳細的說，UTF-8編碼具有以下幾點優點：- ASCII是UTF-8的一個子集。因為一個純ASCII字符串也是一個合法的UTF-8字符串，所以現存的ASCII文本不需要轉換。為傳統的擴展ASCII字符集設計的軟件通常可以不經修改或很少修改就能與UTF-8一起使用。
*使用標準的面向字節的排序例程對UTF-8排序將產生與基於Unicode代碼點排序相同的結果。（儘管這-{只}-有有限的有用性，因為在任何特定語言或文化下都不太可能有仍可接受的文字排列順序。）- UTF-8和UTF-16都是可擴展標記語言文檔的標準編碼。所有其它編碼都必須通過顯式或文本聲明來指定。date=20200110151249 
*任何面向字節的字符串搜索算法都可以用於UTF-8的數據（-{只}-要輸入僅由完整的UTF-8字符組成）。但是，對於包含字符記數的正則表達式或其它結構必須小心。- UTF-8字符串可以由一個簡單的算法可靠地識別出來。就是，一個字符串在任何其它編碼中表現為合法的UTF-8的可能性很低，並隨字符串長度增長而減小。舉例說，字元值C0,C1,F5至FF從來沒有出現。為了更好的可靠性，可以使用正則表達式來統計非法過長和替代值（可以查看 W3 FAQ: Multilingual Forms date=20211011203144 上的驗證UTF-8字符串的正則表達式）。- 與UCS-2的比較：ASCII轉換成UCS-2，在編碼前插入一個0x0。用這些編碼，會含括一些控制符，比如"或 '/'，這在UNIX和一些C函數中，將會產生嚴重錯誤。因此可以肯定，UCS-2不適合作為Unicode的外部編碼，也因此誕生了UTF-8。

**UTF-8 編碼的缺點**

**編寫不良的解析器**
如果一個 UTF-8 解析器寫得很差（並且與當前標準的版本不兼容），那麼它接收到一些偽 UTF-8 時會將其轉換成看似正確實則錯誤的 Unicode 輸出。處理八位表示的校驗例程可能遺漏一些信息。

**不利於正則表達式檢索**
正則表達式可以進行很多高級的英文模糊檢索。例如，a-h表示 a 到 h 間所有字母。
同樣 GBK 編碼的中文也可以這樣利用正則表達式，比如在只知道一個字的讀音而不知道怎麼寫的情況下，也可用正則表達式檢索，因為 GBK 編碼是按讀音排序的。但是 Unicode 漢字不是按讀音排序的，所以不利於用正則表達式檢索。雖然正則表達式檢索並未考慮中文的多音字，但是由於中文的多音字數量不多，不少多音字還是同音不同調類型的多音字，所以大多數情況下正則表達式檢索是還可以接受的。不過 Unicode 漢字按部首排序，因此在只知道一個字的部首而不知道如何發音的情況下，UTF-8 可用正則表達式檢索而 GBK 不行。

**可能無法用舊的 C 語言函式庫讀寫**
由於UTF-8在編碼中可能有著空字元（null character，U+0000），這會導致C語言函示庫以及其延伸的程式解析失敗，因為這些舊有的程式庫使用這個字元來標記字串的結束。然而，之所以說「可能」，是因為這個字元是控制字元，理論上不會出現在 XML 等純文字檔案中。當萬不得已要使用空字元的時候，可能的解決方法是考慮使用 Java 的變種UTF-8 ——使用 0xc0 0x80 來編碼空字元。

**其他**
UTF-8 的 ASCII 字元-{只}-佔用一個字節，比較節省空間，但是更多字元的 UTF-8 編碼佔用的空間就要多出1/2，特別是中文、日文和韓文（CJK）這樣的方塊文字，它們大多需要三個字節。

**UTF-8的衍生物**

**Windows**
雖然不是標準，但許多Windows程序（包括Windows記事本）在UTF-8編碼的檔案的開首加入一段位元組串EF BB BF。這是位元組順序記號U+FEFF的UTF-8編碼結果。對於沒有預期要處理UTF-8的文字編輯器和瀏覽器會顯示成ISO-8859-1字符串ï»¿。

**Posix系統**
Posix系統明確不建議使用字節序掩碼EF BB BF。因為很多文本文件期望以 “#!”（Shebang）開頭指示要運行的程序。Linux系統選擇使用Unicode規範形式Normalization Form C（NFC），即優先使用預組裝字符（precomposed character）而非組合字符序列（combining character sequence）。
2002年9月發佈的Red Hat Linux 8.0才開始正式把大多數區域設置的默認編碼設為UTF-8。此前是各種語言的但字節編碼為主。2004年9月SuSE Linux 9.1開始，缺省編碼遷移為UTF-8。
字符串處理時，使用UTF-8或locale依賴的多字節編碼情形，比使用C語言wchar_t的寬字符固定寬度編碼，要慢1至2個數量級。

**Java**
在通常用法下，Java程序語言在通過InputStreamReader和OutputStreamWriter讀取和寫入串的時候支持標準UTF-8。但是，Java也支持一種非標準的變體UTF-8，供對象的序列化，Java本地界面和在class文件中的嵌入常數時使用的modified-utf-8。

**變種UTF-8**
標準和變種的UTF-8有兩個不同點。第一，空字符（null character，U+0000）使用雙字節的0xc0 0x80，而不是單字節的0x00。這保證了在已編碼字串中沒有嵌入空字節。因為C語言等語言程序中，單字節空字符是用來標誌字串結尾的。當已編碼字串放到這樣的語言中處理，一個嵌入的空字符將把字串一刀兩斷。
第二個不同點是基本多文種平面之外字符的編碼的方法。在標準UTF-8中，這些字符使用4字節形式編碼，而在修正的UTF-8中，這些字符和UTF-16一樣首先表示為代理對（surrogate pairs），然後再像CESU-8那樣按照代理對分別編碼。這樣修正的原因更是微妙。Java中的字符為16位長，因此一些Unicode字符需要兩個Java字符來表示。語言的這個性質蓋過了Unicode的增補平面的要求。儘管如此，為了要保持良好的向後兼容、要改變也不容易了。這個修正的編碼系統保證了一個已編碼字串可以一次編為一個UTF-16碼，而不是一次一個Unicode碼點。不幸的是，這也意味著UTF-8中需要4字節的字符在變種UTF-8中變成需要6字節。
因為變種UTF-8並不是UTF-8，所以用戶在交換信息和使用互聯網的時候需要特別注意不要誤把變種UTF-8當成UTF-8數據。

**Mac OS X**
Mac OS X操作系統使用統一碼正規形式中的分解式標準等價（canonically decomposed Unicode），在文件系統中使用UTF-8編碼進行文件命名，這做法通常被稱為UTF-8-MAC。分解式標準等價中，預組合字符是被禁止使用的，必須以組合字符取代。
這種方法使分類變得非常簡單，但是會搞混那些使用預組合字符為標準、組合字符用來顯示特殊字符的軟件。Mac系統的這種NFD數據是統一碼正規形式（Unicode normalization）的一種格式。而其他系統，包括Windows和Linux，使用統一碼規範的NFC形式，也是W3C標準使用的形式。所以通常NFD數據必須轉換成NFC才能被其他平臺或者網絡使用。
蘋果開發者專區有關於此問題的討論： Apple Q&A 1173 date=20090726001341 。

**MySQL**
MySQL字符編碼集中有兩套UTF-8編碼實現：“utf8”和“utf8mb4”，其中“utf8”是一個字最多佔據3字節空間的編碼實現；而“utf8mb4”則是一個字最多佔據4字節空間的編碼實現，也就是UTF-8的完整實現。這是由於MySQL在4.1版本開始支持UTF-8編碼（當時參考UTF-8草案版本為2279）時，為2003年，並且在同年9月限制了其實現的UTF-8編碼的空間佔用最多為3字節，而UTF-8正式形成標準化文檔（3629）是其之後。限制UTF-8編碼實現的編碼空間佔用一般被認為是考慮到數據庫文件設計的兼容性和讀取最優化，但實際上並沒有達到目的，而且在UTF-8編碼開始出現需要存入非基本多文種平面的Unicode字符（例如emoji字符）時導致無法存入（由於3字節的實現只能存入基本多文種平面內的字符）。直到2010年在5.5版本推出“utf8mb4”來代替、“utf8”重命名為“utf8mb3”並調整“utf8”為“utf8mb3”的別名，並不建議使用舊“utf8”編碼，以此修正遺留問題。

**參閱**
 Alt碼- ASCII- 位元組順序記號- Comparison of email clients#Features- Comparison of Unicode encodings- Character encodings in HTML- ISO/IEC 8859- GB18030- iconv- Unicode and e-mail- Unicode and HTML- 通用字符集- UTF-16- UTF-9和UTF-18- 寬字元

**參考文獻**

**外部連結**
 RFC 3629：UTF-8標準- RFC 2277：IETF policy on character sets and languages-  Rob Pike tells the story of UTF-8's creationdate=20110301051538 -  Original UTF-8 paper- UTF-8 test pages by  University Hannover date=20210417050327  and the  World Wide Web Consortium date=20210414035214 - Unix/Linux:  UTF-8和Unicode的常見問題集date=20180924093018 ， Linux Unicode HOWTO， UTF-8 and Gentoo date=20130720130236 -  The Unicode/UTF-8-character table date=20220120181814  displays UTF-8 in a variety of formats（with Unicode and HTML encoding information）-  Online Tool for URL encoding/decoding according to RFC 3986 and RFC 3629（JavaScript，GPL）-  UTF-8測試頁-  UTF-8 date=20041113044014 

**由統一碼聯盟出版的書**
 The Unicode Standard, Version 5.0, Fifth Edition, The Unicode Consortium, Addison-Wesley Professional,2006年10月27日。ISBN 0-321-48091-0- The Unicode Standard, Version 4.0, The Unicode Consortium, Addison-Wesley Professional，2003年8月27日。ISBN 0-321-18578-1