字元編碼再次剖析
這幾天一直在研究字元編碼,也學到了不少的知識,現在在此進行細細總結。轉載請註明出處。
首先引用一段網上對字元編碼的風趣解釋:
問:計算機是怎麼表示文字的? 他不會. 他就會說0和1.
於是乎 有一幫人為了表示字母和各種符號,就發明了ASCII 實際上就是固定了.一個八位的位元組固定的01排列來表示固定的字元.
比如.字母A 的ASCII碼就是.65. 這個排列就是.01000001.當然,這只是ASCII的編碼,同樣呢,有好多好多種編碼,當然道理是一樣的. 當你要把這個串"A",傳送到別的機器,千萬要記住,你發的不是文字"A",你發過去的是一串01000001(ASCII的時候).
那麼現在我們就要好好理解一下字元和位元組的概念了,一個字元可以由任意整數個位元組進行表示,這也就是說,一個字元可以由一個位元組表示,也可以由多個位元組表示,如在ASCII中一個字元由一個位元組組成,而gb2312和ASCII相容,而且由兩個位元組來表示中文,gbk是gb2312的超集,這也就意味著gb類的字元編碼是變長儲存的。而unicode(預設的實現方式是小頭儲存,即ucs-2)每個字元是由兩個位元組儲存的,且字元的第二個位元組在儲存的時候放在前面,而且通過補0和ascii形成假相容,unicode big endian即所謂的大頭儲存,即字元的第一個位元組放在前面。這兩種unicode的儲存方式造成了儲存空間的浪費,而且與ascii是假相容的。而utf-8解決了上述的兩個問題,目前windows下的預設編碼方式是ansi,即gbk,在vc6.0下是ansi,而在vs2010已經採用了utf-8的編碼方式。
在這裡我們可以使用ultraedit的十六進位制檢視工具來檢視不同編碼的檔案的儲存結構。分別將一個有相同的文字內容的文字檔案另存為ansi編碼,unicode編碼,unicode big endian編碼和utf-8編碼的檔案並且用ultraedit開啟,切換至十六進位制檢視下,進行檢視。可以看到,ansi檔案沒有字首,ascii字元用一個位元組,而中文用兩個位元組。而unicode編碼的檔案有字首FF FE,unicode big endian有檔案字首FE FF,而且可以看到不管任何字元都用兩個位元組表示,其中有很多的00位元組,這勢必會在c語言中字串的操作上帶來很大的不便。utf-8有檔案字首EF BB BF,而且中文是用三個位元組表示的。可以通過檢視vc和vs生成的檔案來檢視其不同的編碼方式。
現在我有一箇中英文混合的utf-8編碼的檔案,想逐行列印其中的每一個字元,那麼可以使用下面的程式:
string path = "C:\\Users\\Yelbosh\\Desktop\\tem.txt";
System.IO.StreamReader sr = new System.IO.StreamReader(path, Encoding.UTF8);
string tempstr = sr.ReadToEnd();
foreach (char tempc in tempstr)
{
Console.WriteLine(tempc.ToString());
}
這裡其他編碼方式的檔案當然也可以,我們最主要使用的是foreach函式,這裡可以通過streamreader按照不同的編碼方式解析檔案的內容。
C#也提供了很多的方法來進行不同編碼方式之間的位元組陣列的轉換。使用encoding的convert方法可以在不同的編碼方式之間進行轉換。
string str = "你好嗎我其實h好的i";
System.Text.Encoding gb2 = System.Text.Encoding.GetEncoding("GB2312");
byte[] b1 = gb2.GetBytes(str);
/*
foreach (byte b in b1)
{
Console.Write(b.ToString("X2")); Console.Write("\t");
}
Console.Write("\n");
* * */
System.Text.Encoding uni = System.Text.Encoding.GetEncoding("Unicode");
string msg = uni.GetString(System.Text.Encoding.Convert(gb2, uni, b1));
Console.Write(msg);
通過實驗我們可以得出正確的結論。其實我們也可以看出字串的顯示已經脫離了底層,已經不屬於編碼方式的範疇了。
但是c#並沒有給出原始碼,那麼計算機如何進行不同編碼方式之間的轉換呢?它是怎麼識別變長儲存呢?如何用c++編寫不同字元編碼方式之間的轉換呢?請繼續關注該部落格~
相關文章
- 【字元編碼】徹底理解字元編碼字元
- 字元編碼字元
- 【字元編碼】字元編碼 && Base64編碼演算法字元演算法
- 字串-字元編碼字串字元
- 聊聊字元編碼字元
- vim字元編碼字元
- 字元編碼 and cpp字元
- 【字元編碼】Java編碼格式探祕字元Java
- 字元編碼轉換字元
- 圖解字元編碼圖解字元
- 理解字元編碼字元
- php_字元編碼PHP字元
- 關於字元編碼字元
- 字元編碼淺談字元
- 字元編碼問題字元
- 【字元編碼】Java字元編碼詳細解答及問題探討字元Java
- 字符集編碼(二):字元編碼模型字元模型
- 字元編碼那些事兒字元
- 1.3.0 Python 字元編碼Python字元
- java字元編碼轉換Java字元
- 字元,位元組和編碼字元
- MySQL 中字元編碼問題MySql字元
- 字元編碼問題記錄字元
- MySQL字元編碼設定方法MySql字元
- javascript字元編碼轉換方法JavaScript字元
- VIM 字元編碼相關操作字元
- iconv字元編碼轉換字元
- 字符集和字元編碼字元
- Python字元編碼詳解Python字元
- spring字元編碼設定Spring字元
- Java IO4:字元編碼Java字元
- 深入剖析go中字串的編碼問題——特殊字元的string怎麼轉byte?Go字串字元
- 【字元編碼系列】Base64編碼原理以及實現字元
- C# 基礎知識:字元編碼、編碼轉換C#字元
- IDEA如何設定編碼格式,字元編碼,全域性編碼和專案編碼格式Idea字元
- 每日 30 秒 ⏱ 字元編碼排雷錄字元
- 字元編碼與檔案處理字元
- MYSQL使用中字元編碼一坑MySql字元