Windows 記事本的 ANSI、Unicode、UTF-8 這三種編碼模式有什麼區別?

Windows 的記事本默認存儲文本文檔編碼是 ANSI,想問一下為了最大跨平台兼容性,應該採用哪種編碼格式比較好?


簡答。一些細節暫無精力查證,如果說錯了還請指出。

一句話建議:涉及兼容性考量時,不要用記事本,用專業的文本編輯器保存為不帶 BOM 的 UTF-8。

* * *

如果是為了跨平台兼容性,只需要知道,在 Windows 記事本的語境中:

  • 所謂的「ANSI」指的是對應當前系統 locale 的遺留(legacy)編碼。[1]
  • 所謂的「Unicode」指的是帶有 BOM 的小端序 UTF-16。[2]
  • 所謂的「UTF-8」指的是帶 BOM 的 UTF-8。[3]

GBK 等遺留編碼最麻煩,所以除非你知道自己在幹什麼否則不要再用了。
UTF-16 理論上其實很好,位元組序也標明了,但 UTF-16 畢竟不常用。
UTF-8 本來是兼容性最好的編碼但 Windows 偏要加 BOM 於是經常出問題。

所以,跨平台兼容性最好的其實就是不用記事本。
建議用 Notepad++ 等正常的專業文本編輯器保存為不帶 BOM 的 UTF-8。

另外,如果文本中所有字元都在 ASCII 範圍內,那麼其實,記事本保存的所謂的「ANSI」文件,和 ASCII 或無 BOM 的 UTF-8 是一樣的。

* * *

阮一峰那篇〈字元編碼筆記:ASCII,Unicode和UTF-8〉的確很有名,但從那篇文章能看出來他其實還是沒完全搞清楚 Unicode 和 UTF-8 的關係。他依舊被 Windows 的混亂措詞誤導。事實上,幾年前我讀完他那篇文章之後依舊一頭霧水,最終還是自己看維基百科看明白的。
所以,那篇文章不值得推薦。

* * *

關於字符集(character set)和編碼(encoding),某幾篇答案中似乎有些混淆。

對於 ASCII、GB 2312、Big5、GBK、GB 18030 之類的遺留方案來說,基本上一個字符集方案只使用一種編碼方案。
比如 ASCII 這部標準本身就直接規定了字元和字元編碼的方式,所以既是字符集又是編碼方案;而 GB 2312 只是一個區位碼形式的字符集標準,不過實際上基本都用 EUC-CN 來編碼,所以提及「GB 2312」時也說的是一個字符集和編碼連鎖的方案;GBK 和 GB 18030 等向後兼容於 GB 2312 的方案也類似。
於是,很多人受這些遺留方案的影響而無法理解字符集和編碼的關係。

對於 Unicode,字符集和編碼是明確區分的。Unicode/UCS 標準首先是個統一的字符集標準。而 Unicode/UCS 標準同時也定義了幾種可選的編碼方案,在標準文檔中稱作「encoding form」,主要包括 UTF-8、UTF-16 和 UTF-32。
所以,對 Unicode 方案來說,同樣的基於 Unicode 字符集的文本可以用多種編碼來存儲、傳輸。
所以,用「Unicode」來稱呼一個編碼方案不合適,並且誤導。

* * *

[1] Windows 里說的「ANSI」其實是 Windows code pages,這個模式根據當前 locale 選定具體的編碼,比如簡中 locale 下是 GBK。把自己這些 code page 稱作「ANSI」是 Windows 的臭毛病。在 ASCII 範圍內它們應該是和 ASCII 一致的。
[2] 把帶有 BOM 的小端序 UTF-16 稱作「Unicode」也是 Windows 的臭毛病。Windows 從 Windows 2000 開始就已經支持 surrogate pair 了,所以已經是 UTF-16 了,「UCS-2」這個說法已經不合適了。UCS-2 只能編碼 BMP 範圍內的字元,從 1996 年起就在 Unicode/ISO 標準中被 UTF-16 取代了(UTF-16 通過蛋疼的 surrogate pair 來編碼超出 BMP 的字元)。都十多年了,求求大家別再誤稱了……
[3] 把帶 BOM 的 UTF-8 稱作「UTF-8」又是 Windows 的臭毛病。如果忽略 BOM,那麼在 ASCII 範圍內與 ASCII 一致。另請參見:「帶 BOM 的 UTF-8」和「無 BOM 的 UTF-8」有什麼區別? http://www.zhihu.com/question/20167122


謝謝 @梁海 邀請。最近狀態不佳,耽誤了這麼久,對不起。

其實前面他自己的回答已經很完善了。我補充一些細節就可以。

ANSI 確實是遺留編碼,在不同語言的系統中編碼不同,這一部分在微軟的術語中叫 code page。比如所謂 GBK 編碼,實際上更多地被叫做 CP936。這個術語是從 IBM 早期的一些工作中繼承下來的,現在也沒改變。但是,代碼頁這個概念在引入更大的字符集時已經遇到了問題,比如當初 GBK 擴展到 GB18030 時,它無法自然地用同一個代碼頁解決問題,不得不使用非常複雜的映射技術在幾個代碼頁中切換才最終達到目的。

所謂微軟的 Unicode,確實是 UTF-16LE。這個問題上 MSDN 文檔在術語運用上有很多前後矛盾的地方,所以很多程序員都不太了解。再加上微軟 SDK 默認的 WCHAR 是兩個位元組,進一步加劇了混亂程度。事實上時至今日,微軟的默認編碼不一定是兩位元組了,因為 Unicode 早已超過了 65536 個字元。

如果是為了跨平台,那麼最有效的辦法確實是堅持使用 UTF-8。不過是否使用 BOM 則未必真的需要很糾結。事實上現代的編輯器都可以很好地處理 BOM,比如 VIM。在 UNIX 環境下不適合使用 BOM 的場合有兩個:一個是 XML,另一個是老舊的 shell 腳本。前者是因為規範里就沒有 BOM 的位置,而後者則是因為歷史原因而不能很好支持。而更大範圍內的應用,比如 Python 腳本,則可以很好地處理 BOM。


先來解釋一下這三種編碼的歷史吧:

ANSI:最早的時候計算機ASCII碼只能表示256個符號(含控制符號),這個字符集表示英文字母足夠,其中,我們鍵盤上可見的符號的編碼範圍是從32到126(大小寫英文字母、數字、英文符號等)。但表示漢字、日語、韓語就不太夠用了,漢字常用字有3000多個。

但是中國人也要用電腦打字,於是,中國人就研究出來了最早的中文字符集GB2312(GBK就是後來的擴展),GB2312的做法是,把ASC碼取值範圍的128~255這個區間挪用了一下,用兩個ASC碼錶示一個漢字,這樣可用的編碼範圍用十六進位表示就是0x8080到0xFFFF,這大概能表示一萬多個符號,足夠了。[注:實際沒用那麼多,GBK的範圍是8140-FEFE]

那個時候,計算機技術還不發達,各個國家搞自己的,比如台灣,也另搞了一套,叫BIG5(俗稱:大五碼),跟大陸的也不太一樣,但方法是類似的,都是用0x80到0xFF這個區間。
然後日語(有編碼JIS)、韓語等等也各搞一套。

這些國家的編碼區間都是重疊的,但同一個漢字(比如有一些漢字同時存在於簡體、繁體、日語漢字中)有不同的編碼,很混亂是不是?但也湊合用了。編碼不同導致了很多麻煩,比如一個網頁,如果你不知道它是什麼編碼的,那麼你可能很難確定它顯示的是什麼,一個字元可能是大陸簡體/台灣繁體/日本漢字,但又完全是不同的幾個字。

所以如果用一些很老的軟體,可能會聽說有中文版/日文版之類的,對應的版本只能在對應的系統上運行。

後來,這個對操作系統的開發實在是太困難了,因為這意味著不同語言的版本,都要重新編碼。於是發明了Unicode。

Unicode這個東西,就是要把地球上所有的語言的符號,都用統一的字符集來表示,一個編碼真正做到了唯一。

Unicode里有幾種方式:

UTF-16BE/LE:UTF-16就是Windows模式的編碼模式(Windows里說的Unicode一般都是指這種編碼),用2個位元組表示任意字元,注意:英文字元也佔2個位元組(變態不?),這種編碼可以表示65536個字元,至於LE和BE,就是一個數值在內存/磁碟上的保存方式,比如一個編碼0x8182,在磁碟上應該是0x81 0x82呢?還是0x82 0x81呢?就是高位是最先保存還是最後保存的問題,前者為BE,後者為LE。

UTF-8:UTF-8則是網頁比較流行的一種格式:用一個位元組表示英文字元,用3個位元組表示漢字,準確的說,UTF-8是用二進位編碼的前綴,如果某個UTF-8的編碼的第一個位元組的最高二進位位是0,則這個編碼佔1位元組,如果是110,則佔2位元組,如果是1110,則佔3位元組……

好了,說了這麼,再來研究Windows的記事本。

Windows早期(至少是95年以前的事情了)是ANSI字符集的,也就是說一個中文文本,在Windows簡體中文版顯示的是中文,到Windows日文版顯示的就不知道是什麼東西了。

後來,Windows支持了Unicode,但當時大部分軟體都是用ANSI編碼的,unicode還不流行,怎麼辦?Windows想了個辦法,就是允許一個默認語言編碼,就是當遇到一個字元串,不是unicode的時候,就用默認語言編碼解釋。(在區域和語言選項里可以改默認語言)

這個默認語言,在不同Windows語言版本里是不同的,在簡體中文版里,是GBK,在繁體中文版里,是BIG5,在日文版里是JIS

而記事本的ANSI編碼,就是這種默認編碼,所以,一個中文文本,用ANSI編碼保存,在中文版里編碼是GBK模式保存的時候,到繁體中文版里,用BIG5讀取,就全亂套了。

記事本也不甘心這樣,所以它要支持Unicode,但是有一個問題,一段二進位編碼,如何確定它是GBK還是BIG5還是UTF-16/UTF-8?記事本的做法是在TXT文件的最前面保存一個標籤,如果記事本打開一個TXT,發現這個標籤,就說明是unicode。標籤叫BOM,如果是0xFF 0xFE,是UTF16LE,如果是0xFE 0xFF則UTF16BE,如果是0xEF 0xBB 0xBF,則是UTF-8。如果沒有這三個東西,那麼就是ANSI,使用操作系統的默認語言編碼來解釋。

Unicode的好處就是,不論你的TXT放到什麼語言版本的Windows上,都能正常顯示。而ANSI編碼則不能。(UTF-8的好處是在網路環境下,比較節約流量,畢竟網路里英文的數據還是最多的)

舉例:

同樣一段中文文本(可以插入一些英文),保存成ANSI/Unicode/UTF-8,三個文件。

修改windows的默認語言為日語之類的(WIN7的改法是:控制面板-時鐘、語言和區域-更改顯示語言-區域和語言-管理-非unicode程序語言-更改區域設置/WNIXP改法是:控制面板-區域和語言選項-非unicode程序語言)。

修改完要求重啟,重啟以後,再打開這三個文件,ANSI的編碼全亂了,其餘兩個都正常顯示,這就是UNICODE的作用。

另外,為什麼記事本、開始菜單什麼的還是正確的中文呢?明明我已經改了默認語言了?因為它們的程序編碼也是unicode的。

要把txt發給國外的朋友或者用在非中文的操作系統/軟體里,那麼你的編碼最好選擇unicode

-完-


Unicode是FFFE後面接著UTF-16字元串的二進位文件,UTF-8是EFBBBF後面接著UTF-8字元串的二進位文件、ANSI是有時候會被解釋為當前locale對應的code page的字元串的二進位文件。


他們都是二進位文件,不要有太多幻想。


發布過編碼規範的組織有 GB、微軟、Unicode 聯盟和 ISO 等,互相之間有的兼容,有的不兼容。
GB 是國標,中國的一個發布編碼規範的機構,可以忽略掉,通用性太差了。
微軟在 GB2312 的基礎上擴展了 GBK,也可以忽略掉。
UTF-8(一種編碼方式) 是 Unicode(一種標準) 的實現方式。記事本把 Unicode 和 UTF-8 並列,我不太懂它什麼意思。
ANSI 並不是確定的一種編碼,在簡體中文操作系統指的是 GB2312,在繁體操作系統指的是 BIG5。一句話,最好用 UTF-8。
多說一句:不要使用 Windows 自帶的記事本!說記事本是垃圾,一點不為過。


基本的問題是:非英語字元需要擴展 只面向英文的ASCii編碼。

ANSI:泛指最早每種國家語言各自實現的編碼方式,各個編碼互相之間不兼容,比較省空間。

Unicode:一套抽象的兼容所有常用語言的編碼方式,但是不適合計算機系統直接存儲。

UTF-8:一種將unicode轉換成適合計算機存儲的方式,
相對其他的UTF-xx省空間,同時又可以和ASCII混用,結構相對複雜,底層處理相對慢。

UTF-16,UTF-32:另外的unicode存儲編碼,結構簡單,不能和ASCII混用。

BOM:一種為了跨平台設計的文件起始標記,但很多程序沒去處理這個,用了BOM反而常造成問題。


ASCII是古老的編碼,那個時候還不區分字符集和編碼,基本可以看作合二為一的東西。

Unicode嚴格來說是字符集,可以有多種編碼。

UTF-8是一種Unicode的編碼。

兼容性最好的,我記得好像是UTF-8不帶BOM頭。

註: 字符集(char set)就是字元的集合,收錄了一定數量的字元。每個字元有對應的ID值,叫碼點(code point)。實際存儲的時候,不一定是直接存儲字元串的碼點(比如,為了節約空間),要進行轉換。這個轉換規則就是編碼。


+1

總算搞明白了為啥我的記事本弄出來的utf-8不能跨平台。此坑綿長。謝謝各位大大。


可不可以認為Unicode是標準,UTF8是實現?


windows系統中ANSI一般指在地化的字符集及其編碼方式,根據系統版本及相關語言選項而有所不同,H7F以內採用ASCII編碼,在簡中環境一般還包括GB2312及後來的GBK、GB18030編碼(這三個為字符集,但通常也隱含EUC-CN編碼的含義),利用的是ASCII擴展編碼空間,即所謂製表符(該空間也包含拉丁、希臘字母等非英文字元),因此包含有表格字元的文本在簡中環境下,表格部分常常會被顯示成漢字。實際上狹義的ANSI編碼應該就是所謂ASCII及其擴展碼部分,記事本等地方出現的ANSI是極不嚴謹的。

Unicode是國際標準的字符集,在windows中常常也特指UTF-16(el小頭)編碼,每個字元占倆位元組。UTF-8則字元所佔長度為變長。

實際上windows及微軟其他軟體中,很多表述不是特別嚴謹,比如ASC()函數,該函數原本指取首字元的ASCII碼值,而描述中是取首字元的ANSI碼值,但在VB中參量為中文字元的時候和在老版本BASIC中返回的結果卻大不同,老版本為H80到HFF之間,而VB中返回的卻為UTF-16碼值。

就兼容及經濟性來講,不同的環境這幾種編碼各有優缺點。兼容性來說其實對我來說差不多,只要盡量使用同一種編碼就不會對我產生困擾,具體還要考慮到所用到的軟體環境兼容哪一種。而經濟性么,源代碼、網頁代碼之類的東西用utf-8看起來比較經濟,但對於中文為主的文本性的內容而言(例如文學作品等),雙位元組的UTF-16更省,而且個人感覺UTF16的文件很整齊,計數和查找比較方便。「ANSI」則對較老的環境兼容性很好,也不存在BOM,在不涉及複雜多語言環境的情況下也是個不錯的選擇。


ansi比較好 他是適應你操作系統語言的編碼格式


以上解釋都或多或少問題。關於寬位元組編碼,跨平台的(windows/Linux/MacOS X 開發者最有體會,加上我因為開發電子書程序,系統的研究和測試了開源字元串轉換庫iconv庫這個東西,這個問題應該是比較了解。我寫過一個比較長的分析文章。具體請看 http://blog.chinaunix.net/uid-20587912-id-405017.html 《漢字編碼與Linux中文處理》 .近來偏向Mac OS X下開發居多,因此深有體會。
這裡簡單總結一下:

1.ANSI 就是ASCII編碼。一個英文字元佔一個字元
2.GB2312 是國內利用ASCII控制字元(即碼值超過127)的兩個字元形成一個漢字的原理。在DOS時代和windows 3.1時代用的就是這個方案,必須要外掛系統來解決顯示問題。 同時代台灣搞一個BIG5編碼也是相同原理,但是碼值有衝突,所以那個時代txt 亂碼是很頭痛問題。 一個漢字相當於兩個字元。但是這個格式用得還是很多。網上txt 中文小說幾乎都是這個格式,還有歌詞文件 lrc也是這個格式。後來為兼容繁體字,後推出一個GBK 大字集。

3. 國標組織為了解決世界各國的寬字元編碼不統一的問題,搞出一UNICODE編碼。把世界常用的語言的字元編一編碼採用兩個字元。世界約有幾萬字元(主要中文吃了一片),因此不同國家用不同代碼區(code page 區別)(無論英文,漢字,泰文等)均是如此。 windows是內核採用了UNICODE編碼。 但是在應用程序這一級為了兼容老的程序還有一套API,留給原來的應用程序來用。

4.到了Linux 和Mac OS X, 內核的編碼採用是UTF-8,寬字元如漢字,採用的UTF-8編碼。這個主要是針對網路傳輸的,從名字就可以看出來,UCS Transfer For .這個編碼的特點除了統一編碼外,還有的碼值是變長,即一個字元可以由1-4字元表示,英文就與ASCII對應,漢字最短是兩個字元,最長是四個字元,這個可以把傳輸字元量減到最小。

UTF8 與UNICODE沒有規律的轉換關係,兩者編碼是有衝突的。
--------------------------------------------

跨平台開發者要碰到一些問題: 在windows寫的漢字,比如在程序中漢字注釋(無論是UNICODE,還是GB2312)在LINUX下UTF8顯示均是亂碼。反過來也是一樣。
當然有一些windows工具如UltraEdit 能直接識別,那是應用程序自己作了轉換。

至於說哪種格式通用,沒有定例,完全看應用程序的要求。我舉幾個常見例子。
1. 歌詞文件 lrc,從我看的研究來看,哪個平台都是採用ANSI + GBK編碼的。你隨便從QQ音樂下載幾個歌詞就知道了。現在從網上下的小說txt ,基於是GBK格式的。

2.java內碼指定是UNICODE編碼,所以你在哪一個平台的Eclipse里輸入的漢字均採用UNICODE編碼,這樣在Mac OS X 你可以發現在Eclipse寫的漢字,用XCode 打開就亂碼。

3. XML這一些格式,裡面要求是UTF-8,你可以看第一句就註明是UTF-8格式。


阮一峰解釋得不錯:http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html

1)ANSI是默認的編碼方式。對於英文文件是ASCII編碼,對於簡體中文文件是GB2312編碼(只針對Windows簡體中文版,如果是繁體中文版會採用Big5碼)。
2)Unicode編碼指的是UCS-2編碼方式,即直接用兩個位元組存入字元的Unicode碼。這個選項用的little endian格式。
3)Unicode big endian編碼與上一個選項相對應。我在下一節會解釋little endian和big endian的涵義。
4)UTF-8編碼,也就是上一節談到的編碼方法。


推薦閱讀:

為什麼維基百科的編輯器不是所見即所得的?

TAG:文本編輯器 | Unicode統一碼 | UTF-8 | Windows記事本 |