免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開(kāi)通VIP
字符編碼的概念

字符集為每個(gè)字符分配了一個(gè)唯一的編號(hào),通過(guò)這個(gè)編號(hào)就能找到對(duì)應(yīng)的字符。在編程過(guò)程中我們經(jīng)常會(huì)使用字符,而使用字符的前提就是把字符放入內(nèi)存中,毫無(wú)疑問(wèn),放入內(nèi)存中的僅僅是字符的編號(hào),而不是真正的字符實(shí)體。

這就拋出了一個(gè)問(wèn)題,如何才能將字符編號(hào)放入內(nèi)存中呢?

對(duì)于 ASCII 字符集,這很容易。ASCII 總共包含 128 個(gè)字符,用 7 個(gè)比特位(Bit)恰好能夠存儲(chǔ),不過(guò)考慮到計(jì)算機(jī)一般把字節(jié)(Byte)作為基本單元,為了操作方便,我們不妨用一個(gè)字節(jié)(也就是 8 個(gè)比特位)來(lái)存儲(chǔ) ASCII。這樣雖然浪費(fèi)了一個(gè)比特位,但是讀寫效率提高了。

但是對(duì)于 Unicode,問(wèn)題就沒(méi)有這么簡(jiǎn)單了。Unicode 目前已經(jīng)包含了上百萬(wàn)的字符,位置靠前的字符用一個(gè)字節(jié)就能存儲(chǔ),位置靠后的字符用三個(gè)字節(jié)才能存儲(chǔ)。我們可以為所有字符都分配三個(gè)字節(jié)的內(nèi)存,也可以為編號(hào)小的字符分配一個(gè)字節(jié)或者兩個(gè)字節(jié)的內(nèi)存,而為編號(hào)大的字符分配三個(gè)字節(jié)的內(nèi)存。

這兩種方案各有優(yōu)缺點(diǎn),請(qǐng)讀者看下面的分析。

字符集和字符編碼不是一個(gè)概念,字符集定義了文字和二進(jìn)制的對(duì)應(yīng)關(guān)系,為字符分配了唯一的編號(hào),而字符編碼規(guī)定了如何將文字的編號(hào)存儲(chǔ)到內(nèi)存中。有的字符集在制定時(shí)就考慮到了編碼的問(wèn)題,是和編碼結(jié)合在一起的;有的字符集只管制定字符的編號(hào),至于怎么編碼,是其他人的事情。

方案1:為每個(gè)字符分配固定長(zhǎng)度的內(nèi)存

一種方案是為每個(gè)字符分配固定長(zhǎng)度的內(nèi)存,并且這塊內(nèi)存要足夠大,可以容納下所有的字符編號(hào)。這種方案最簡(jiǎn)單,直接將字符編號(hào)放入內(nèi)存中即可,不需要任何轉(zhuǎn)換,并且以后在字符串中定位字符、修改字符都非常容易。

字符串就是一串連續(xù)的字符序列,它們?cè)趦?nèi)存中按次序挨著存放。在C語(yǔ)言中,字符串由雙引號(hào)" "包圍起來(lái)。

目前的 Unicode 已經(jīng)收錄了上百萬(wàn)的字符,至少需要三個(gè)字節(jié)才能容納下所有的字符編號(hào)。假設(shè)字符串"A3中¥"的 Unicode 編碼值(十六進(jìn)制形式)分別是 2A、31、DA49、BB672C,那么它們?cè)趦?nèi)存中的存儲(chǔ)形式為:


在幾乎所有的字符集中,常用字符的編號(hào)往往比較小,罕見(jiàn)字符的編號(hào)往往比較大,包括 Unicode 在內(nèi)。

A3是 ASCII 編碼中的字符,Unicode 為了兼容 ASCII,在設(shè)計(jì)時(shí)刻意保留了原來(lái) ASCII 中字符的編號(hào),所以英文字母和阿拉伯?dāng)?shù)字在 Unicode 中的編號(hào)都非常小,用一個(gè)字節(jié)足以容納。是一個(gè)漢字,編號(hào)比較大,一般要用兩個(gè)字節(jié)才能容納。可以看做是一個(gè)極其少見(jiàn),或者只有極少數(shù)地區(qū)才會(huì)使用到的字符,這樣的字符編號(hào)往往比較大,有時(shí)候需要三個(gè)字節(jié)才能容納。

是人民幣符號(hào),是漢字文化的一部分,它和其它漢字一樣,實(shí)際上是用兩個(gè)字節(jié)存儲(chǔ)的,不過(guò)這里我們?yōu)榱搜菔?,故意犯錯(cuò)地說(shuō)它需要三個(gè)字節(jié)。

上圖中帶灰色背景的字節(jié)是沒(méi)有用到的字節(jié),它們就是被浪費(fèi)掉的一部分內(nèi)存空間,這就是用固定長(zhǎng)度的內(nèi)存來(lái)存儲(chǔ)字符編號(hào)的缺點(diǎn):常用字符的編號(hào)都比較小,這種方案會(huì)浪費(fèi)很多內(nèi)存空間,對(duì)于以英文為主的國(guó)家,比如美國(guó)、加拿大、英國(guó)等,內(nèi)存利用率甚至?xí)陀?50%。

方案2:為每個(gè)字符分配盡量少的內(nèi)存

既然上面的方案有缺點(diǎn),那我們就來(lái)改進(jìn)一下。改進(jìn)的思路也很明確,就是把空閑的內(nèi)存壓縮掉,為每個(gè)字符分配盡量少的字節(jié),例如,A3分配一個(gè)字節(jié)足以,分配兩個(gè)字節(jié)足以,如下圖所示:


這樣雖然沒(méi)有了空閑字節(jié),不浪費(fèi)任何內(nèi)存空間了,但是又出現(xiàn)新的問(wèn)題了:如果我不告訴你,你怎么知道2A表示一個(gè)字符,而不是2A31或者2A31DA才表示一個(gè)字符呢?后面的字符也有類似的問(wèn)題。

對(duì)于第一種方案,每個(gè)字符占用的字節(jié)數(shù)是固定的,很容易區(qū)分各個(gè)字符;而這種方案,不同的字符占用的字節(jié)數(shù)不同,字符之間也沒(méi)有特殊的標(biāo)記,計(jì)算機(jī)是無(wú)法定位字符的。

這種方案還需要改進(jìn),必須讓不同的字符編碼有不同的特征,并且字符處理程序也需要調(diào)整,要根據(jù)這些特征去識(shí)別不同的字符。

要想讓不同的字符編碼有不同的特征,可以從兩個(gè)方面下手:

1) 一是從字符集本身下手,在設(shè)計(jì)字符集時(shí),刻意讓不同的字符編號(hào)有不同的特征。

例如,對(duì)于編號(hào)較小的、用一個(gè)字節(jié)足以容納的字符,我們就可以規(guī)定這個(gè)字符編號(hào)的最高位(Bit)必須是 0;對(duì)于編號(hào)較大的、要用兩個(gè)字節(jié)存儲(chǔ)的字符,我們就可以規(guī)定這個(gè)字符編號(hào)的高字節(jié)的最高位必須是 1,低字節(jié)的最高位必須是 0;對(duì)于編號(hào)更大的、需要三個(gè)字節(jié)存儲(chǔ)的字符,我們就可以規(guī)定這個(gè)字符編號(hào)的所有字節(jié)的最高位都必須是 1。

程序在定位字符時(shí),從前往后依次掃描,如果發(fā)現(xiàn)當(dāng)前字節(jié)的最高位是 0,那么就把這一個(gè)字節(jié)作為一個(gè)字符編號(hào)。如果發(fā)現(xiàn)當(dāng)前字節(jié)的最高位是 1,那么就繼續(xù)往后掃描,如果后續(xù)字節(jié)的最高位是 0,那么就把這兩個(gè)字節(jié)作為一個(gè)字符編號(hào);如果后續(xù)字節(jié)的最高位是 1,那么就把挨著的三個(gè)字節(jié)作為一個(gè)字符編號(hào)。

這種方案的缺點(diǎn)很明顯,它會(huì)導(dǎo)致字符集不連續(xù),中間留出大量空白區(qū)域,這些空白區(qū)域不能定義任何字符。

2) 二是從字符編號(hào)下手,可以設(shè)計(jì)一種轉(zhuǎn)換方案,字符編號(hào)在存儲(chǔ)之前先轉(zhuǎn)換為有特征的、容易定位的編號(hào),讀取時(shí)再按照相反的過(guò)程轉(zhuǎn)換成字符本來(lái)的編號(hào)。

那么,轉(zhuǎn)換后的編號(hào)要具備什么樣的特征呢?其實(shí)也可以像上面一樣,根據(jù)字節(jié)的最高位是 0 還是 1 來(lái)判斷字符到底占用了幾個(gè)字節(jié)。

相比第一種方案,這種方案有缺點(diǎn)也有優(yōu)點(diǎn):

  • 缺點(diǎn)就是多了轉(zhuǎn)換過(guò)程,字符在存儲(chǔ)和讀取時(shí)要經(jīng)過(guò)轉(zhuǎn)換,效率低;

  • 優(yōu)點(diǎn)就是在制定字符集時(shí)不用考慮存儲(chǔ)的問(wèn)題,可以任意排布字符。

Unicode 到底使用哪種編碼方案

Unicode 是一個(gè)獨(dú)立的字符集,它并不是和編碼綁定的,你可以采用第一種方案,為每個(gè)字符分配固定長(zhǎng)度的內(nèi)存,也可以采用第二種方案,為每個(gè)字符分配盡量少的內(nèi)存。

需要注意的是,Unicode 只是一個(gè)字符集,在制定的時(shí)候并沒(méi)有考慮編碼的問(wèn)題,所以采用第二種方案時(shí),就不能從字符集本身下手了,只能從字符編號(hào)下手,這樣在存儲(chǔ)和讀取時(shí)都要進(jìn)行適當(dāng)?shù)霓D(zhuǎn)換。

Unicode 可以使用的編碼有三種,分別是:

  • UFT-8:一種變長(zhǎng)的編碼方案,使用 1~6 個(gè)字節(jié)來(lái)存儲(chǔ);

  • UFT-32:一種固定長(zhǎng)度的編碼方案,不管字符編號(hào)大小,始終使用 4 個(gè)字節(jié)來(lái)存儲(chǔ);

  • UTF-16:介于 UTF-8 和 UTF-32 之間,使用 2 個(gè)或者 4 個(gè)字節(jié)來(lái)存儲(chǔ),長(zhǎng)度既固定又可變。

UTF 是 Unicode Transformation Format 的縮寫,意思是“Unicode轉(zhuǎn)換格式”,后面的數(shù)字表明至少使用多少個(gè)比特位(Bit)來(lái)存儲(chǔ)字符。

1) UTF-8

UTF-8 的編碼規(guī)則很簡(jiǎn)單:如果只有一個(gè)字節(jié),那么最高的比特位為 0;如果有多個(gè)字節(jié),那么第一個(gè)字節(jié)從最高位開(kāi)始,連續(xù)有幾個(gè)比特位的值為 1,就使用幾個(gè)字節(jié)編碼,剩下的字節(jié)均以 10 開(kāi)頭。

具體的表現(xiàn)形式為:

  • 0xxxxxxx:?jiǎn)巫止?jié)編碼形式,這和 ASCII 編碼完全一樣,因此 UTF-8 是兼容 ASCII 的;

  • 110xxxxx 10xxxxxx:雙字節(jié)編碼形式;

  • 1110xxxx 10xxxxxx 10xxxxxx:三字節(jié)編碼形式;

  • 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx:四字節(jié)編碼形式。

xxx 就用來(lái)存儲(chǔ) Unicode 中的字符編號(hào)。

下面是一些字符的編碼實(shí)例(綠色部分表示本來(lái)的 Unicode 編號(hào)):

字符N??
Unicode 編號(hào)(二進(jìn)制)010011101110011000101110 11101100
Unicode 編號(hào)(十六進(jìn)制)4EE62E EC
UTF-8 編碼(二進(jìn)制)0100111011000011 1010011011100010 10111011 10101100
UTF-8 編碼(十六進(jìn)制)4EC3 A6E2 BB AC

對(duì)于常用的字符,它的 Unicode 編號(hào)范圍是 0 ~ FFFF,用 1~3 個(gè)字節(jié)足以存儲(chǔ),只有及其罕見(jiàn),或者只有少數(shù)地區(qū)使用的字符才需要 4~6個(gè)字節(jié)存儲(chǔ)。

2) UTF-32

UTF-32 是固定長(zhǎng)度的編碼,始終占用 4 個(gè)字節(jié),足以容納所有的 Unicode 字符,所以直接存儲(chǔ) Unicode 編號(hào)即可,不需要任何編碼轉(zhuǎn)換。浪費(fèi)了空間,提高了效率。

3) UTF-16

UFT-16 比較奇葩,它使用 2 個(gè)或者 4 個(gè)字節(jié)來(lái)存儲(chǔ)。

對(duì)于 Unicode 編號(hào)范圍在 0 ~ FFFF 之間的字符,UTF-16 使用兩個(gè)字節(jié)存儲(chǔ),并且直接存儲(chǔ) Unicode 編號(hào),不用進(jìn)行編碼轉(zhuǎn)換,這跟 UTF-32 非常類似。

對(duì)于 Unicode 編號(hào)范圍在 10000~10FFFF 之間的字符,UTF-16 使用四個(gè)字節(jié)存儲(chǔ),具體來(lái)說(shuō)就是:將字符編號(hào)的所有比特位分成兩部分,較高的一些比特位用一個(gè)值介于 D800~DBFF 之間的雙字節(jié)存儲(chǔ),較低的一些比特位(剩下的比特位)用一個(gè)值介于 DC00~DFFF 之間的雙字節(jié)存儲(chǔ)。

如果你不理解什么意思,請(qǐng)看下面的表格:

Unicode 編號(hào)范圍
(十六進(jìn)制)
具體的 Unicode 編號(hào)
(二進(jìn)制)
UTF-16 編碼編碼后的
字節(jié)數(shù)
0000 0000 ~ 0000 FFFFxxxxxxxx xxxxxxxxxxxxxxxx xxxxxxxx2
0001 0000---0010 FFFFyyyy yyyy yyxx xxxx xxxx110110yy yyyyyyyy 110111xx xxxxxxxx4

位于 D800~0xDFFF 之間的 Unicode 編碼是特別為四字節(jié)的 UTF-16 編碼預(yù)留的,所以不應(yīng)該在這個(gè)范圍內(nèi)指定任何字符。如果你真的去查看 Unicode 字符集,會(huì)發(fā)現(xiàn)這個(gè)區(qū)間內(nèi)確實(shí)沒(méi)有收錄任何字符。

UTF-16 要求在制定 Unicode 字符集時(shí)必須考慮到編碼問(wèn)題,所以真正的 Unicode 字符集也不是隨意編排字符的。

總結(jié)

只有 UTF-8 兼容 ASCII,UTF-32 和 UTF-16 都不兼容 ASCII,因?yàn)樗鼈儧](méi)有單字節(jié)編碼。

如果你希望查看完整的 Unicode 字符集,以及各種編碼方式,請(qǐng)猛擊:https://unicode-table.com/cn/

雖然這個(gè)網(wǎng)站有時(shí)候無(wú)法訪問(wèn),但它是最好的一個(gè)查看 Unicode 字符集的網(wǎng)站。

GB2312、Shift-JIS 等國(guó)家(地區(qū))字符集怎么編碼

GB2312、GBK、Shift-JIS 等特定國(guó)家的字符集都是在 ASCII 的基礎(chǔ)上發(fā)展起來(lái)的,它們都兼容 ASCII,所以只能采用變長(zhǎng)的編碼方案:用一個(gè)字節(jié)存儲(chǔ) ASCII 字符,用多個(gè)字節(jié)存儲(chǔ)本國(guó)字符。

以 GB2312 為例,該字符集收錄的字符較少,所以使用 1~2 個(gè)字節(jié)編碼。

  • 對(duì)于 ASCII 字符,使用一個(gè)字節(jié)存儲(chǔ),并且該字節(jié)的最高位是 0;

  • 對(duì)于中國(guó)的字符,使用兩個(gè)字節(jié)存儲(chǔ),并且規(guī)定每個(gè)字節(jié)的最高位都是 1。

由于單字節(jié)和雙字節(jié)的最高位不一樣,所以很容易區(qū)分一個(gè)字符到底用了幾個(gè)字節(jié)。

寬字符和窄字符(多字節(jié)字符)

有的編碼方式采用 1~n 個(gè)字節(jié)存儲(chǔ),是變長(zhǎng)的,例如 UTF-8、GB2312、GBK 等;如果一個(gè)字符使用了這種編碼方式,我們就將它稱為多字節(jié)字符,或者窄字符。

有的編碼方式是固定長(zhǎng)度的,不管字符編號(hào)大小,始終采用 n 個(gè)字節(jié)存儲(chǔ),例如 UTF-32、UTF-16 等;如果一個(gè)字符使用了這種編碼方式,我們就將它稱為寬字符。

Unicode 字符集可以使用窄字符的方式存儲(chǔ),也可以使用寬字符的方式存儲(chǔ);GB2312、GBK、Shift-JIS 等國(guó)家編碼一般都使用窄字符的方式存儲(chǔ);ASCII 只有一個(gè)字節(jié),無(wú)所謂窄字符和寬字符。

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
ASCII, GB2312, Unicode , UTF-8 - 靈感點(diǎn)滴
UTF-8和UTF-16使用對(duì)比
編碼方式之ASCII、ANSI、Unicode概述
叫板阮一峰老師:你真的理解了 Unicode 與 UTF
字符編碼
《源碼探秘 CPython》19. 字符集和字符編碼
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服