ANSI,UTF8等等這些格式

之前一直在糾結這些格式到底有什麼區別,有時候因爲格式的問題會讓人抓狂。


下面通過實戰來分析下:

下面在windows上建立一個txt文檔。txt的優勢是沒有文件頭,這樣比較好分析。



ANSI格式:


可以看到,0D0A是\r\n,可以忽略,這裏的蛤被識別成B8 F2


UTF-8無BOM:


這裏的英文字母還是ASCII格式,漢字在這裏被識別成 E8 9B A4


UTF-8:


英文字母是ASCII,這裏前面多了三個字節: EF BB BF,這個東西可能是BOM

蛤被識別成E8 9B A4


UCS2 大端:

這裏有一個前綴 FE FF

這裏的0123對應的30,31,32被擴展成兩個字節,\r\n也是。

漢字被識別成 86 E4

可以注意到,對於0,識別出 0030,是大端排列的



UCS2小端:

這裏有一個前綴 FF FE

另外一個區別是數字和漢字對應的編碼是小端排列的




那麼這裏來總結一下:



1.除了UCS2,其他格式的ASCII字母都是一個字節。

2.UCS2和UTF8都帶有前綴

3.對於ANSI和UCS2,漢字被識別成2個字節,對於UTF8,漢字被識別成三個字節(實際上UTF8中,應該隨着漢字而變化)。


這裏的UCS2不論什麼都識別成兩個字節,比較變態。



網絡上建議爲了兼容性,使用無BOM的UTF8

那麼有沒有BOM有什麼區別呢?知乎上這麼解答(http://www.zhihu.com/question/20167122):

下面的粗體字都是從這裏拷過來的:

UTF-8 不需要 BOM,儘管 Unicode 標準允許在 UTF-8 中使用 BOM。所以不含 BOM 的 UTF-8 纔是標準形式

後面又提到:在 UTF-8 文件中放置 BOM 主要是微軟的習慣。    這樣就釋懷了,原來是微軟乾的,好像系統自帶的記事本廣受吐槽。


微軟在 UTF-8 中使用 BOM 是因爲這樣可以把 UTF-8 和 ASCII 等編碼明確區分開,但這樣的文件在 Windows 之外的操作系統裏會帶來問題。

「UTF-8」和「帶 BOM 的 UTF-8」的區別就是有沒有 BOM。即文件開頭有沒有 U+FEFF。

在網頁上使用BOM是個錯誤。BOM設計出來不是用來支持HTML和XML的。要識別文本編碼,HTML有charset屬性,XML有encoding屬性,沒必要拉BOM撐場面
其實說BOM是個壞習慣也不盡然很多shell出於兼容的考慮不檢測BOM最後回頭想想,似乎也真就只有Windows堅持用BOM了。


看起來BOM(EFBBBF)就是讓編輯器識別他是UTF8,編輯器如果把它識別爲字符的話就會出錯。



UTF8的格式如下:

1、對於單字節符號,字節第一位爲0,後面7位表示字節編碼。
2、對於n字節符號,第一字節的前n位都設爲1,第n+1位爲0,其餘位位編碼位置。

上面的蛤的表示是E8 9B A4,它有三個字節,第一個字節前面是1110,也正好符合。




那麼什麼是UCS2呢?UCS2在windows中指代Unicode

這裏(http://demon.tw/programming/utf-16-ucs-2.html)有解答:

簡單的說,UTF-16可看成是UCS-2的父集。在沒有輔助平面字符(surrogate code points)前,UTF-16與UCS-2所指的是同一的意思

所謂微軟的 Unicode,確實是 UTF-16LE,那就是UCS2 LE了。



這裏(http://www.zhihu.com/question/20650946)又講了:

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

原來這裏的ANSI實際上是GBK這些編碼啊!

而記事本的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是FFFE後面接着UTF-16字符串的二進制文件,UTF-8是EFBBBF後面接着UTF-8字符串的二進制文件、ANSI是有時候會被解釋爲當前locale對應的code page的字符串的二進制文件。(還是根據前綴來的啊)


看到這一句話,說明GB開頭的也可以無視了:

GB 是國標,中國的一個發佈編碼規範的機構,可以忽略掉,通用性太差了。微軟在 GB2312 的基礎上擴展了 GBK,也可以忽略掉。



 那麼UTF8 without BOM怎麼解析呢,沒有文件頭??

一些代碼文件裏面一般是在最前面加入了文件格式的說明,比如HTML的charset,python的開頭一行也有。


這裏有一個回答解決了疑惑(如何自動識別UTF8)

UTF-8 can be auto-detected better by contents than by BOM. The method is simple: try to read the file (or a string) as UTF-8 and if that succeeds, assume that the data is UTF-8. Otherwise assume that it is CP1252 (or some other 8 bit encoding). Any non-UTF-8 eight bit encoding will almost certainly contain sequences that are not permitted by UTF-8. Pure ASCII (7 bit) gets interpreted as UTF-8, but the result is correct that way too.

原來它是智能識別,根據UTF8特定的格式來校驗它是否是UTF8




還有一些問題仍未解決的:

Qt中出現的Latin1,ASCII是什麼?爲什麼Qt經常亂碼?


1.根據百度百科的介紹,Latin1包含ASCII,具有一些其他的字符。當然了,使用英文的時候這些都可以。

2.local8bit應該是本地編碼。QString內部應該要保存UTF8,然後輸入輸出的時候需要轉換一下:


QString str = QString::fromLocal8Bit("漢字");//輸入

std::cout << "Local Output:" << str.local8Bit() << endl;//輸出



根據這篇博客的介紹:

http://blog.csdn.net/brave_heart_lxl/article/details/7186631


可以看出源代碼文件的編碼格式對其也有影響。而且QString賦值的時候必須要告訴QString自己是什麼編碼。


一般給個char*的時候,Qt並不知道你採用的是什麼編碼,而是需要告訴它你採用的是什麼編碼。

正確的操作應該這樣:

告訴Qt 默認的編碼(cpp源文件的編碼需要對應):

QTextCodec::setCodecForCStrings(QTextCodec::codecForName("GBK"));
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
設置QString默認採用的編碼。而究竟採用哪一個,一般來說就是源代碼是GBK,就用GBK,源代碼是UTF-8就用UTF-8。


還有涉及到路徑的問題,那就有一個萬能的辦法:

    QTextCodec *codec = QTextCodec::codecForName("UTF-8");

    QTextCodec::setCodecForTr(codec);

    QTextCodec::setCodecForLocale(QTextCodec::codecForLocale()); //外部路徑,非文件中的代碼,windows使用的gb2312,這裏就採用了gb2312
    QTextCodec::setCodecForCStrings(QTextCodec::codecForLocale());//















發佈了29 篇原創文章 · 獲贊 0 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章