程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C#編程總結(十)字符編碼

C#編程總結(十)字符編碼

編輯:C#入門知識

相信大家一定遇到過亂碼的問題,為什麼會亂碼呢?輸出的數據怎麼就跟輸入的不一樣呢?   最近在總結加密問題,也遇到了同樣的困擾。所以今天來集中解決這個問題。   什麼是字符?   字符是指計算機中使用的字母、數字、字和符號,包括:1、2、3、A、B、C、~!·#¥%……—*()——+等等。   字符集(Charset)   字符集(Charset)是一個系統支持的所有抽象字符的集合。   字符是各種文字和符號的總稱,包括各國家文字、標點符號、圖形符號、數字等。   什麼是字符編碼?   字符編碼(Character Encoding):簡單的說就是建立自然語言與機器語言之間的對應關系。是一套法則,使用該法則能夠對自然語言的字符的一個集合(如字母表或音節表),與其他東西的一個集合(如號碼或電脈沖)進行配對。即在符號集合與數字系統之間建立對應關系,它是信息處理的一項基本技術。通常人們用符號集合(一般情況下就是文字)來表達信息。而以計算機為基礎的信息處理系統則是利用元件(硬件)不同狀態的組合來存儲和處理信息的。元件不同狀態的組合能代表數字系統的數字,因此字符編碼就是將符號轉換為計算機可以接受的數字系統的數,稱為數字代碼。    計算機中的信息包括數據信息和控制信息,數據信息又可分為數值和非數值信息。非數值信息和控制信息包括了字母、各種控制符號、圖形符號等,它們都以二進制編碼方式存入計算機並得以處理,這種對字母和符號進行編碼的二進制代碼稱為字符代碼(Character Code)。計算機中常用的字符編碼有ASCII碼(美國標准信息交換碼)和EBCDIC碼(擴展的BCD交換碼)。   在 ASCII 編碼中,一個英文字母字符存儲需要1個字節。在 GB 2312 編碼或 GBK 編碼中,一個漢字字符存儲需要2個字節。在UTF-8編碼中,一個英文字母字符存儲需要1個字節,一個漢字字符儲存需要3到4個字節。在UTF-16編碼中,一個英文字母字符或一個漢字字符存儲都需要2個字節(Unicode擴展區的一些漢字存儲需要4個字節)。在UTF-32編碼中,世界上任何字符的存儲都需要4個字節。    困擾與疑惑?   1、為什麼會有字符編碼?   含義介紹中已經給出了解釋,字符編碼就是讓計算機識別自然語言。   2、為什麼會有這麼多的字符集?   計算機發展分不同階段,最開始只是美國通用,建立了ASCII碼,但是一些歐洲國家字符無法使用ASCII碼,然後就對ASCII進行了擴展補充,後來中國要使用計算機,為了標記漢語,定義了GB2312、GBK、BIG5等,還有其他一些字符集。   3、就沒有一種統一的字符集嗎?   有,Unicode   4、UTF8與Unicode是什麼關系?   UTF8是Unicode的一種實現方式。    常用的幾種編碼   1. ASCII碼   ASCII(American Standard Code for Information Interchange,美國信息交換標准代碼)是基於拉丁字母的一套電腦編碼系統。   ASCII字符集:主要包括控制字符(回車鍵、退格、換行鍵等);可顯示字符(英文大小寫字符、阿拉伯數字和西文符號)。   特點:單字節編碼,只包含大小寫英文字母、標點符號及其他符號。   ASCII編碼:將ASCII字符集轉換為計算機可以接受的數字系統的數的規則。使用7位(bits)表示一個字符,共128字符;但是7位編碼的字符集只能支持128個字符,為了表示更多的歐洲常用字符對ASCII進行了擴展,ASCII擴展字符集使用8位(bits)表示一個字符,共256字符。   計算機為美國人發明,開始的時候也只能滿足自己,所以說此編碼很有局限性。在其他的國家、其他語種無法使用此編碼集。   根據ASCII碼的編碼規則,最多只能標識256個字符,但是世界上有那麼多語言,漢字就多達10萬左右,那麼多字符,顯然很有局限性。   以下是ASCII代碼表,表二為其擴展表。               2、中文編碼   2.1 GB2312   特點:簡體中文字符集,采用雙字節編碼。   GB2312或GB2312-80是中國國家標准簡體中文字符集,全稱《信息交換用漢字編碼字符集·基本集》,又稱GB0,由中國國家標准總局發布,1981年5月1日實施。GB2312編碼通行於中國大陸;新加坡等地也采用此編碼。中國大陸幾乎所有的中文系統和國際化的軟件都支持GB2312。GB2312的出現,基本滿足了漢字的計算機處理需要,它所收錄的漢字已經覆蓋中國大陸99.75%的使用頻率。對於人名、古漢語等方面出現的罕用字,GB2312不能處理,這導致了後來GBK及GB 18030漢字字符集的出現。    2.2 GBK   特點:擴展了GB2312,包括非常用簡體漢字、繁體字、日語及朝鮮漢字等。   由於GB 2312只收錄6763個漢字,有不少漢字,如部分在GB 2312-80推出以後才簡化的漢字(如"啰"),部分人名用字(如中國前總理朱镕基的"镕"字),台灣及香港使用的繁體字,日語及朝鮮語漢字等,並未有收錄在內。於是廠商微軟利用GB 2312-80未使用的編碼空間,收錄GB 13000.1-93全部字符制定了GBK編碼。    2.3 BIG編碼   特點:繁體中文,流行於台灣、香港與澳門,采用雙字節編碼。   Big5,又稱為大五碼或五大碼,是使用繁體中文(正體中文)社區中最常用的電腦漢字字符集標准,共收錄13,060個漢字。中文碼分為內碼及交換碼兩類,Big5屬中文內碼,知名的中文交換碼有CCCII、CNS11643。Big5雖普及於台灣、香港與澳門等繁體中文通行區,但長期以來並非當地的國家標准,而只是業界標准。Big5碼是一套雙字節字符集,使用了雙八碼存儲方法,以兩個字節來安放一個字。第一個字節稱為"高位字節",第二個字節稱為"低位字節"。"高位字節"使用了0x81-0xFE,"低位字節"使用了0x40-0x7E,及0xA1-0xFE。    2.4 GB18030   GB 18030,全稱:國家標准GB 18030-2005《信息技術 中文編碼字符集》,是中華人民共和國現時最新的內碼字集,是GB 18030-2000《信息技術 信息交換用漢字編碼字符集 基本集的擴充》的修訂版。與GB 2312-1980完全兼容,與GBK基本兼容,支持GB 13000及Unicode的全部統一漢字,共收錄漢字70244個。   3.Unicode   特點:涵蓋所有的文字、符號,每個符號都有獨一無二的編碼,全世界通用,四字節存儲。   Unicode(統一碼、萬國碼、單一碼)是一種在計算機上使用的字符編碼。Unicode 是為了解決傳統的字符編碼方案的局限而產生的,它為每種語言中的每個字符設定了統一並且唯一的二進制編碼,以滿足跨語言、跨平台進行文本轉換、處理的要求。1990年開始研發,1994年正式公布。隨著計算機工作能力的增強,Unicode也在面世以來的十多年裡得到普及。   具體的符號對應表,可以查詢unicode.org,或者專門的漢字對應表。   全部編碼采用4字節存儲,如果是ASCII碼,本來是單字節存儲的,也要用四字節來存儲,前三個字節都是0,很浪費空間。   4.UTF-8   特點:Unicode的一種實現方式,變長的編碼方式,可以使用1~4個字節表示一個符號,根據不同的符號而變化字節長度。   互聯網的普及,強烈要求出現一種統一的編碼方式。UTF-8就是在互聯網上使用最廣的一種Unicode的實現方式。其他實現方式還包括UTF-16(字符用兩個字節或四個字節表示)和UTF-32(字符用四個字節表示),不過在互聯網上基本不用。   UTF-8最大的一個特點,就是它是一種變長的編碼方式。它可以使用1~4個字節表示一個符號,根據不同的符號而變化字節長度。   UTF-8的編碼規則很簡單,只有二條:   1)對於單字節的符號,字節的第一位設為0,後面7位為這個符號的unicode碼。因此對於英語字母,UTF-8編碼和ASCII碼是相同的。   2)對於n字節的符號(n>1),第一個字節的前n位都設為1,第n+1位設為0,後面字節的前兩位一律設為10。剩下的沒有提及的二進制位,全部為這個符號的unicode碼。   下表總結了編碼規則,字母x表示可用編碼的位。   Unicode符號范圍 | UTF-8編碼方式 (十六進制) | (二進制) --------------------+--------------------------------------------- 0000 0000-0000 007F | 0xxxxxxx 0000 0080-0000 07FF | 110xxxxx 10xxxxxx 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx   跟據上表,解讀UTF-8編碼非常簡單。如果一個字節的第一位是0,則這個字節單獨就是一個字符;如果第一位是1,則連續有多少個1,就表示當前字符占用多少個字節。   下面,還是以漢字"嚴"為例,演示如何實現UTF-8編碼。   已知"嚴"的unicode是4E25(100111000100101),根據上表,可以發現4E25處在第三行的范圍內(0000 0800-0000 FFFF),因此"嚴"的UTF-8編碼需要三個字節,即格式是"1110xxxx 10xxxxxx 10xxxxxx"。然後,從"嚴"的最後一個二進制位開始,依次從後向前填入格式中的x,多出的位補0。這樣就得到了,"嚴"的UTF-8編碼是"11100100 10111000 10100101",轉換成十六進制就是E4B8A5。    為什麼會出現亂碼?   由於字符編碼不同,一種編碼無法兼容另一種編碼,就會出現亂碼。   舉個簡單例子,ASCII編碼轉為UTF8是沒問題的,但是當UTF8轉ASCII碼就可能出問題。   舉個簡單例子:   你如果是一個會英語的中國人,當一個英國人給你說話時,你明白他的意思,但回答的是中文,他估計不會聽懂的。       通過以下例子,來對具體的編碼規則以及亂碼情況進行比較吧:   復制代碼 using System; using System.Collections.Generic; using System.Linq; using System.Text;   namespace EncodingSample {     class Program     {         /// <summary>         ///          /// </summary>         /// <param name="args"></param>         static void Main(string[] args)         {             //英文字符串             string str_en = "Welcome to the Encoding world.";             //簡體中文             string str_cn = "歡迎來到編碼世界!";             //繁體中文             string str_tw = "歡迎來到編碼世界";               Encoding defaultEncoding = Encoding.Default;             Console.WriteLine("默認編碼:{0}", defaultEncoding.BodyName);                 Encoding dstEncoding = null;             //ASCII碼             Console.WriteLine("----ASCII編碼----");             dstEncoding = Encoding.ASCII;             OutputByEncoding(defaultEncoding, dstEncoding, str_en);             OutputByEncoding(defaultEncoding, dstEncoding, str_cn);             OutputByEncoding(defaultEncoding, dstEncoding, str_tw);               OutputBoundary();               //GB2312             Console.WriteLine("----GB2312編碼----");             dstEncoding = Encoding.GetEncoding("GB2312");             OutputByEncoding(defaultEncoding, dstEncoding, str_en);             OutputByEncoding(defaultEncoding, dstEncoding, str_cn);             OutputByEncoding(defaultEncoding, dstEncoding, str_tw);               OutputBoundary();               //BIG5             Console.WriteLine("----BIG5編碼----");             dstEncoding = Encoding.GetEncoding("BIG5");             OutputByEncoding(defaultEncoding, dstEncoding, str_en);             OutputByEncoding(defaultEncoding, dstEncoding, str_cn);             OutputByEncoding(defaultEncoding, dstEncoding, str_tw);               OutputBoundary();               //Unicode             Console.WriteLine("----Unicode編碼----");             dstEncoding = Encoding.Unicode;             OutputByEncoding(defaultEncoding, dstEncoding, str_en);             OutputByEncoding(defaultEncoding, dstEncoding, str_cn);             OutputByEncoding(defaultEncoding, dstEncoding, str_tw);               OutputBoundary();               //UTF8             Console.WriteLine("----UTF8編碼----");             dstEncoding = Encoding.UTF8;             OutputByEncoding(defaultEncoding, dstEncoding, str_en);             OutputByEncoding(defaultEncoding, dstEncoding, str_cn);             OutputByEncoding(defaultEncoding, dstEncoding, str_tw);               Console.ReadKey();           }         /// <summary>         ///          /// </summary>         /// <param name="srcEncoding">原編碼</param>         /// <param name="dstEncoding">目標編碼</param>         /// <param name="srcBytes">原</param>         public static void OutputByEncoding(Encoding srcEncoding,Encoding dstEncoding,string srcStr)         {             byte[] srcBytes = srcEncoding.GetBytes(srcStr);             Console.WriteLine("Encoding.GetBytes: {0}", BitConverter.ToString(srcBytes));             byte[] bytes = Encoding.Convert(srcEncoding, dstEncoding, srcBytes);             Console.WriteLine("Encoding.GetBytes: {0}", BitConverter.ToString(bytes));             string result = dstEncoding.GetString(bytes);             Console.WriteLine("Encoding.GetString: {0}", result);         }         /// <summary>         /// 分割線         /// </summary>         public static void OutputBoundary()         {             Console.WriteLine("------------------------------------");         }     } }

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved