日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

字节、编码、字符、字符集 专题

發布時間:2023/12/4 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 字节、编码、字符、字符集 专题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1.2 字符,字節,字符串

理解編碼的關鍵,是要把字符的概念和字節的概念理解準確。這兩個概念容易混淆,我們在此做一下區分:

?

 概念描述舉例
字符人們使用的記號,抽象意義上的一個符號。'1', '中', 'a', '$', '¥', ……
字節計算機中存儲數據的單元,一個8位的二進制數,是一個很具體的存儲空間。0x01, 0x45, 0xFA, ……
ANSI 字符串在內存中,如果“字符”是以?ANSI 編碼形式存在的,一個字符可能使用一個字節或多個字節來表示,那么我們稱這種字符串為?ANSI 字符串或者多字節字符串"中文123" (占7字節)
UNICODE 字符串在內存中,如果“字符”是以在 UNICODE 中的序號存在的,那么我們稱這種字符串為UNICODE 字符串或者寬字節字符串。L"中文123" (占10字節)

?

由于不同 ANSI 編碼所規定的標準是不相同的,因此,對于一個給定的多字節字符串,我們必須知道它采用的是哪一種編碼規則,才能夠知道它包含了哪些“字符”。而對于?UNICODE 字符串來說,不管在什么環境下,它所代表的“字符”內容總是不變的。

1.3 字符集與編碼

各個國家和地區所制定的不同 ANSI 編碼標準中,都只規定了各自語言所需的“字符”。比如:漢字標準(GB2312)中沒有規定韓國語字符怎樣存儲。這些 ANSI 編碼標準所規定的內容包含兩層含義:

  • 使用哪些字符。也就是說哪些漢字,字母和符號會被收入標準中。所包含“字符”的集合就叫做“字符集”。
  • 規定每個“字符”分別用一個字節還是多個字節存儲,用哪些字節來存儲,這個規定就叫做“編碼”。
  • 各個國家和地區在制定編碼標準的時候,“字符的集合”和“編碼”一般都是同時制定的。因此,平常我們所說的“字符集”,比如:GB2312, GBK, JIS 等,除了有“字符的集合”這層含義外,同時也包含了“編碼”的含義。

    UNICODE 字符集”包含了各種語言中使用到的所有“字符”。用來給 UNICODE 字符集編碼的標準有很多種,比如:UTF-8, UTF-7, UTF-16, UnicodeLittle, UnicodeBig 等。

    1.4 常用的編碼簡介

    簡單介紹一下常用的編碼規則,為后邊的章節做一個準備。在這里,我們根據編碼規則的特點,把所有的編碼分成三類:

    ?

    分類編碼標準說明
    單字節字符編碼ISO-8859-1最簡單的編碼規則,每一個字節直接作為一個 UNICODE 字符。比如,[0xD6, 0xD0] 這兩個字節,通過 iso-8859-1 轉化為字符串時,將直接得到 [0x00D6, 0x00D0] 兩個 UNICODE 字符,即 "?D"。
    反之,將 UNICODE 字符串通過 iso-8859-1 轉化為字節串時,只能正常轉化 0~255 范圍的字符。
    ANSI 編碼GB2312, BIG5, Shift_JIS, ISO-8859-2 ……把 UNICODE 字符串通過 ANSI 編碼轉化為“字節串”時,根據各自編碼的規定,一個 UNICODE 字符可能轉化成一個字節或多個字節。
    反之,將字節串轉化成字符串時,也可能多個字節轉化成一個字符。比如,[0xD6, 0xD0] 這兩個字節,通過 GB2312 轉化為字符串時,將得到 [0x4E2D] 一個字符,即 '中' 字。
    “ANSI 編碼”的特點: 1. 這些“ANSI 編碼標準”都只能處理各自語言范圍之內的 UNICODE 字符。 2. “UNICODE 字符”與“轉換出來的字節”之間的關系是人為規定的。
    UNICODE 編碼UTF-8, UTF-16, UnicodeBig ……與“ANSI 編碼”類似的,把字符串通過 UNICODE 編碼轉化成“字節串”時,一個 UNICODE 字符可能轉化成一個字節或多個字節。
    與“ANSI 編碼”不同的是: 1. 這些“UNICODE 編碼”能夠處理所有的 UNICODE 字符。 2. “UNICODE 字符”與“轉換出來的字節”之間是可以通過計算得到的。

    ?

    我們實際上沒有必要去深究每一種編碼具體把某一個字符編碼成了哪幾個字節,我們只需要知道“編碼”的概念就是把“字符”轉化成“字節”就可以了。對于“UNICODE 編碼”,由于它們是可以通過計算得到的,因此,在特殊的場合,我們可以去了解某一種“UNICODE 編碼”是怎樣的規則。

    ?

    2. 字符與編碼在程序中的實現 2.1 程序中的字符與字節

    在 C++ 和 Java 中,用來代表“字符”和“字節”的數據類型,以及進行編碼的方法:

    ?

    類型或操作C++Java
    字符wchar_tchar
    字節charbyte
    ANSI 字符串char[]byte[]
    UNICODE 字符串wchar_t[]String
    字節串→字符串mbstowcs(), MultiByteToWideChar()string = new String(bytes, "encoding")
    字符串→字節串wcstombs(), WideCharToMultiByte()bytes = string.getBytes("encoding")

    ?

    以上需要注意幾點:

  • Java 中的 char 代表一個“UNICODE 字符(寬字節字符)”,而 C++ 中的 char 代表一個字節。
  • MultiByteToWideChar() 和 WideCharToMultiByte() 是 Windows API 函數
  • 2.3 Java 中相關實現方法

    字符串類 String 中的內容是 UNICODE 字符串:

    ?

    // Java 代碼,直接寫中文
    String string = "中文123";

    // 得到長度為 5,因為是 5 個字符
    System.out.println(string.length());

    ?

    字符串 I/O 操作,字符與字節轉換操作。在 Java 包 java.io.* 中,以“Stream”結尾的類一般是用來操作“字節串”的類,以“Reader”,“Writer”結尾的類一般是用來操作“字符串”的類。

    // 字符串與字節串間相互轉化// 按照 GB2312 得到字節(得到多字節字符串) byte [] bytes = string.getBytes("GB2312");// 從字節按照 GB2312 得到 UNICODE 字符串 string = new String(bytes, "GB2312");// 要將 String 按照某種編碼寫入文本文件,有兩種方法:// 第一種辦法:用 Stream 類寫入已經按照指定編碼轉化好的字節串 OutputStream os = new FileOutputStream("1.txt"); os.write(bytes); os.close();// 第二種辦法:構造指定編碼的 Writer 來寫入字符串 Writer ow = new OutputStreamWriter(new FileOutputStream("2.txt"), "GB2312"); ow.write(string); ow.close();/* 最后得到的 1.txt 和 2.txt 都是 7 個字節 */

    如果 java 的源程序編碼與當前默認 ANSI 編碼不符,則在編譯的時候,需要指明一下源程序的編碼。比如:

    E:\>javac -encoding BIG5 Hello.java

    以上需要注意區分源程序的編碼與 I/O 操作的編碼,前者是在編譯時起作用,后者是在運行時起作用。?

    3. 幾種誤解,以及亂碼產生的原因和解決辦法 3.1 容易產生的誤解

    ?

     對編碼的誤解
    誤解一在將“字節串”轉化成“UNICODE 字符串”時,比如在讀取文本文件時,或者通過網絡傳輸文本時,容易將“字節串”簡單地作為單字節字符串,采用每“一個字節”就是“一個字符”的方法進行轉化。

    而實際上,在非英文的環境中,應該將“字節串”作為 ANSI 字符串,采用適當的編碼來得到 UNICODE 字符串,有可能“多個字節”才能得到“一個字符”。

    通常,一直在英文環境下做開發的程序員們,容易有這種誤解。
    誤解二在 DOS,Windows 98 等非 UNICODE 環境下,字符串都是以 ANSI 編碼的字節形式存在的。這種以字節形式存在的字符串,必須知道是哪種編碼才能被正確地使用。這使我們形成了一個慣性思維:“字符串的編碼”。

    當 UNICODE 被支持后,Java 中的 String 是以字符的“序號”來存儲的,不是以“某種編碼的字節”來存儲的,因此已經不存在“字符串的編碼”這個概念了。只有在“字符串”與“字節串”轉化時,或者,將一個“字節串”當成一個 ANSI 字符串時,才有編碼的概念。

    不少的人都有這個誤解。

    ?

    第一種誤解,往往是導致亂碼產生的原因。第二種誤解,往往導致本來容易糾正的亂碼問題變得更復雜。

    在這里,我們可以看到,其中所講的“誤解一”,即采用每“一個字節”就是“一個字符”的轉化方法,實際上也就等同于采用 iso-8859-1 進行轉化。因此,我們常常使用 bytes = string.getBytes("iso-8859-1") 來進行逆向操作,得到原始的“字節串”。然后再使用正確的 ANSI 編碼,比如 string = new String(bytes, "GB2312"),來得到正確的“UNICODE 字符串”。?

    3.2 非 UNICODE 程序在不同語言環境間移植時的亂碼

    非 UNICODE 程序中的字符串,都是以某種 ANSI 編碼形式存在的。如果程序運行時的語言環境與開發時的語言環境不同,將會導致 ANSI 字符串的顯示失敗。

    比如,在日文環境下開發的非 UNICODE 的日文程序界面,拿到中文環境下運行時,界面上將顯示亂碼。如果這個日文程序界面改為采用 UNICODE 來記錄字符串,那么當在中文環境下運行時,界面上將可以顯示正常的日文。

    由于客觀原因,有時候我們必須在中文操作系統下運行非 UNICODE 的日文軟件,這時我們可以采用一些工具,比如,南極星,AppLocale 等,暫時的模擬不同的語言環境。?

    3.3 網頁提交字符串

    當頁面中的表單提交字符串時,首先把字符串按照當前頁面的編碼,轉化成字節串。然后再將每個字節轉化成 "%XX" 的格式提交到 Web 服務器。比如,一個編碼為 GB2312 的頁面,提交 "中" 這個字符串時,提交給服務器的內容為 "%D6%D0"。

    在服務器端,Web 服務器把收到的 "%D6%D0" 轉化成 [0xD6, 0xD0] 兩個字節,然后再根據 GB2312 編碼規則得到 "中" 字。

    在 Tomcat 服務器中,request.getParameter() 得到亂碼時,常常是因為前面提到的“誤解一”造成的。默認情況下,當提交 "%D6%D0" 給 Tomcat 服務器時,request.getParameter() 將返回 [0x00D6, 0x00D0] 兩個 UNICODE 字符,而不是返回一個 "中" 字符。因此,我們需要使用 bytes = string.getBytes("iso-8859-1") 得到原始的字節串,再用 string = new String(bytes, "GB2312") 重新得到正確的字符串 "中"。?

    3.4 從數據庫讀取字符串

    通過數據庫客戶端(比如 ODBC 或 JDBC)從數據庫服務器中讀取字符串時,客戶端需要從服務器獲知所使用的 ANSI 編碼。當數據庫服務器發送字節流給客戶端時,客戶端負責將字節流按照正確的編碼轉化成 UNICODE 字符串。

    如果從數據庫讀取字符串時得到亂碼,而數據庫中存放的數據又是正確的,那么往往還是因為前面提到的“誤解一”造成的。解決的辦法還是通過 string = new String( string.getBytes("iso-8859-1"), "GB2312") 的方法,重新得到原始的字節串,再重新使用正確的編碼轉化成字符串。?

    3.5 電子郵件中的字符串

    當一段 Text 或者 HTML 通過電子郵件傳送時,發送的內容首先通過一種指定的字符編碼轉化成“字節串”,然后再把“字節串”通過一種指定的傳輸編碼(Content-Transfer-Encoding)進行轉化得到另一串“字節串”。比如,打開一封電子郵件源代碼,可以看到類似的內容:

    ?

    Content-Type: text/plain;
    charset="gb2312"
    Content-Transfer-Encoding: base64

    sbG+qcrQuqO17cf4yee74bGjz9W7+b3wudzA7dbQ0MQNCg0KvPKzxqO6uqO17cnnsaPW0NDEDQoNCg==

    ?

    最常用的 Content-Transfer-Encoding 有 Base64 和 Quoted-Printable 兩種。在對二進制文件或者中文文本進行轉化時,Base64 得到的“字節串”比 Quoted-Printable 更短。在對英文文本進行轉化時,Quoted-Printable 得到的“字節串”比 Base64 更短。

    郵件的標題,用了一種更簡短的格式來標注“字符編碼”和“傳輸編碼”。比如,標題內容為 "中",則在郵件源代碼中表示為:

    ?

    // 正確的標題格式
    Subject: =?GB2312?B?1tA=?=

    ?其中,

    • 第一個“=?”與“?”中間的部分指定了字符編碼,在這個例子中指定的是 GB2312。
    • “?”與“?”中間的“B”代表 Base64。如果是“Q”則代表 Quoted-Printable。
    • 最后“?”與“?=”之間的部分,就是經過 GB2312 轉化成字節串,再經過 Base64 轉化后的標題內容。

    如果“傳輸編碼”改為 Quoted-Printable,同樣,如果標題內容為 "中":

    ?

    // 正確的標題格式
    Subject: =?GB2312?Q?=D6=D0?=

    如果閱讀郵件時出現亂碼,一般是因為“字符編碼”或“傳輸編碼”指定有誤,或者是沒有指定。比如,有的發郵件組件在發送郵件時,標題 "中":

    // 錯誤的標題格式
    Subject: =?ISO-8859-1?Q?=D6=D0?=

    這樣的表示,實際上是明確指明了標題為 [0x00D6, 0x00D0],即 "?D",而不是 "中"。?

    4. 幾種錯誤理解的糾正誤解:“ISO-8859-1 是國際編碼?”

    非也。iso-8859-1 只是單字節字符集中最簡單的一種,也就是“字節編號”與“UNICODE 字符編號”一致的那種編碼規則。當我們要把一個“字節串”轉化成“字符串”,而又不知道它是哪一種 ANSI 編碼時,先暫時地把“每一個字節”作為“一個字符”進行轉化,不會造成信息丟失。然后再使用 bytes = string.getBytes("iso-8859-1") 的方法可恢復到原始的字節串。

    誤解:“Java 中,怎樣知道某個字符串的內碼?”

    Java 中,字符串類 java.lang.String 處理的是 UNICODE 字符串,不是 ANSI 字符串。我們只需要把字符串作為“抽象的符號的串”來看待。因此不存在字符串的內碼的問題。

  • http://wenwen.sogou.com/z/q181295395.htm

  • 1. gb2312
    規定: 一個小于127的字符的意義與原來相同, 但兩個大于127的字符連在一起時, 就表示一個漢字, 前面的一個字節(他稱之為高字節)從0xA1用到 0xF7, 后面一個字節(低字節)
    從0xA1到0xFE, 這樣我們就可以組合出大約7000多個簡體漢字了.
    在這些編碼里, 我們還把數學符號,羅馬希臘的 字母,日文的假名們都編進去了, 連在 ASCII 里本來就有的數字,標點,字母都統統重新編了兩個字節長的編碼, 這就是常說的"全角"字符, 而原來在127號以下的那些就叫"半角"字符了.
    中國人民看到這樣很不錯, 于是就把這種漢字方案叫做 "GB2312". GB2312 是對 ASCII的中文擴展.
    2. GBK
    但是中國的漢字太多了, 我們很快就就發現有許多人的人名沒有辦法在這里打出來. 于是我們不得不繼續把 GB2312 沒有用到的碼位找出來用上.

    后來還是不夠用, 于是干脆不再要求低字節一定是127號之后的內碼, 只要第一個字節是大于127就固定表示這是一個漢字的開始, 不管后面跟的是不是擴展字 符集里的內容. 結果擴展之后的編碼方案被稱為 "GBK" 標準, GBK 包括了 GB2312 的所有內容, 同時又增加了近20000個新的漢字(包括繁體字)和符號.
    Note: Unicode相關的基礎知識請參數上一篇博文.


    3. Unicode與GBK互轉

    3.1 GBK --> Unicode

    Unicode 與 GBK 是兩個完全不樣的字符編碼方案, 其兩者沒有直接關系, 要對其進行相
    互轉換, 最直接最高效的方法是查表.
    GBK與Unicode的映射表可以從網上下載:
    ????http://www.gnu.org/directory/libiconv.html
    顯然, 只需要把下載下來的映射表用一個二維數組表示即可,
  • InputStreamReader和OutputStreamWriter:InputStreamReader是字節流通向字符流的橋梁:它使用指定的charset?讀取字節并將其解碼為字符。它使用的字符集可以由名稱指定或顯式給定,或者可以接受平臺默認的字符集。

    OutputStreamWriter是字符流通向字節流的橋梁:可使用指定的charset?將要寫入流中的字符編碼成字節。它使用的字符集可以由名稱指定或顯式給定,否則將接受平臺默認的字符集。

  • 總結

    以上是生活随笔為你收集整理的字节、编码、字符、字符集 专题的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。