UTF-8编码的字符串拆分成单字、获取UTF-8字符串的字符个数的代码及原理(c++实现)...
1. ASCII碼
在計(jì)算機(jī)內(nèi)部,全部的信息終于都表示為一個(gè)二進(jìn)制的字符串。每個(gè)二進(jìn)制位(bit)有0和1兩種狀態(tài),因此八個(gè)二進(jìn)制位就能夠組合出256種狀態(tài),這被稱(chēng)為一個(gè)字節(jié)(byte)。也就是說(shuō),一個(gè)字節(jié)一共能夠用來(lái)表示256種不同的狀態(tài),每個(gè)狀態(tài)相應(yīng)一個(gè)符號(hào),就是256個(gè)符號(hào),從0000000到11111111。
上個(gè)世紀(jì)60年代,美國(guó)制定了一套字符編碼,對(duì)英語(yǔ)字符與二進(jìn)制位之間的關(guān)系,做了統(tǒng)一規(guī)定。這被稱(chēng)為ASCII碼,一直沿用至今。
ASCII碼一共規(guī)定了128個(gè)字符的編碼,比方空格“SPACE”是32(二進(jìn)制00100000),大寫(xiě)的字母A是65(二進(jìn)制01000001)。這128個(gè)符號(hào)(包含32個(gè)不能打印出來(lái)的控制符號(hào)),僅僅占用了一個(gè)字節(jié)的后面7位,最前面的1位統(tǒng)一規(guī)定為0。
2. Unicode
英語(yǔ)用128個(gè)符號(hào)編碼就夠了,可是用來(lái)表示其它語(yǔ)言,128個(gè)符號(hào)是不夠的。因此,非常多歐洲國(guó)家發(fā)明了非常多非ASCII碼,相同用一個(gè)字節(jié),用最高位為1的區(qū)間(既128~255)來(lái)擴(kuò)展原來(lái)的ASCII碼,當(dāng)中一種比較有名的就是IBM字符編碼。這樣一來(lái),這些歐洲國(guó)家使用的編碼體系,能夠表示最多256個(gè)符號(hào)。可是,這里又出現(xiàn)了新的問(wèn)題。不同的國(guó)家有不同的字母,因此,哪怕它們都使用256個(gè)符號(hào)的編碼方式,代表的字母卻不一樣。比方,130在法語(yǔ)編碼中代表了é,在希伯來(lái)語(yǔ)編碼中卻代表了字母Gimel (?),在俄語(yǔ)編碼中又會(huì)代表還有一個(gè)符號(hào)。可是無(wú)論如何,全部這些編碼方式中,0—127表示的符號(hào)是一樣的,不一樣的僅僅是128—255的這一段。
至于亞洲國(guó)家的文字,使用的符號(hào)就很多其它了,漢字就多達(dá)10萬(wàn)左右。一個(gè)字節(jié)僅僅能表示256種符號(hào),肯定是不夠的,就必須使用多個(gè)字節(jié)表達(dá)一個(gè)符號(hào)。比方,中文簡(jiǎn)體常見(jiàn)的編碼方式是GB2312,使用兩個(gè)字節(jié)表示一個(gè)漢字,所以理論上最多能夠表示256x256=65536個(gè)符號(hào)。
世界上存在著多種編碼方式,同一個(gè)二進(jìn)制數(shù)字能夠被解釋成不同的符號(hào)。因此,要想打開(kāi)一個(gè)文本文件,就必須知道它的編碼方式,否則用錯(cuò)誤的編碼方式解讀,就會(huì)出現(xiàn)亂碼。為什么電子郵件經(jīng)常出現(xiàn)亂碼?就是由于發(fā)信人和收信人使用的編碼方式不一樣。
能夠想象,假設(shè)有一種編碼,將世界上全部的符號(hào)都納入當(dāng)中。每個(gè)符號(hào)都給予一個(gè)獨(dú)一無(wú)二的編碼,那么亂碼問(wèn)題就會(huì)消失。這就是Unicode,就像它的名字都表示的,這是一種全部符號(hào)的編碼。
Unicode當(dāng)然是一個(gè)非常大的集合,如今的規(guī)模能夠容納100多萬(wàn)個(gè)符號(hào)。每一個(gè)符號(hào)的編碼都不一樣。須要注意的是,Unicode僅僅是一個(gè)符號(hào)集,它僅僅規(guī)定了符號(hào)的二進(jìn)制代碼,卻沒(méi)有規(guī)定這個(gè)二進(jìn)制代碼應(yīng)該怎樣存儲(chǔ)。
3. UTF-8
互聯(lián)網(wǎng)的普及,強(qiáng)烈要求出現(xiàn)一種統(tǒng)一的編碼方式。UTF-8就是在互聯(lián)網(wǎng)上使用最廣的一種unicode的實(shí)現(xiàn)方式。其它實(shí)現(xiàn)方式還包含UTF-16和UTF-32,只是在互聯(lián)網(wǎng)上基本不用。反復(fù)一遍,這里的關(guān)系是,UTF-8是Unicode的實(shí)現(xiàn)方式之中的一個(gè)。
UTF-8最大的一個(gè)特點(diǎn),就是它是一種變長(zhǎng)的編碼方式。它能夠使用1~6個(gè)字節(jié)表示一個(gè)符號(hào),依據(jù)不同的符號(hào)而變化字節(jié)長(zhǎng)度。
UTF-8的編碼規(guī)則非常easy,僅僅有二條:
1)對(duì)于單字節(jié)的符號(hào),字節(jié)的第一位設(shè)為0,后面7位為這個(gè)符號(hào)的unicode碼。因此對(duì)于英語(yǔ)字母,UTF-8編碼和ASCII碼是同樣的。
2)對(duì)于n字節(jié)的符號(hào)(n>1),第一個(gè)字節(jié)的前n位都設(shè)為1,第n+1位設(shè)為0,后面字節(jié)的前兩位一律設(shè)為10。剩下的沒(méi)有提及的二進(jìn)制位,所有為這個(gè)符號(hào)的unicode碼。
如表:?
1字節(jié) 0xxxxxxx?
2字節(jié) 110xxxxx 10xxxxxx?
3字節(jié) 1110xxxx 10xxxxxx 10xxxxxx?
4字節(jié) 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx?
5字節(jié) 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx?
6字節(jié) 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx?
因此UTF-8中能夠用來(lái)表示字符編碼的實(shí)際位數(shù)最多有31位,即上表中x所表示的位。除去那些控制位(每字節(jié)開(kāi)頭的10等),這些x表示的位與UNICODE編碼是一一相應(yīng)的,位高低順序也同樣。?
實(shí)際將UNICODE轉(zhuǎn)換為UTF-8編碼時(shí)應(yīng)先去除高位0,然后依據(jù)所剩編碼的位數(shù)決定所需最小的UTF-8編碼位數(shù)。?
因此那些基本ASCII字符集中的字符(UNICODE兼容ASCII)僅僅須要一個(gè)字節(jié)的UTF-8編碼(7個(gè)二進(jìn)制位)便能夠表示。?
依據(jù)此規(guī)則,能夠非常方便的把UTF-8編碼的字符串拆分成單字集合,代碼例如以下:
size_t utf8_to_charset(const std::string &input, std::set<std::string> &output) {std::string ch; for (size_t i = 0, len = 0; i != input.length(); i += len) {unsigned char byte = (unsigned)input[i];if (byte >= 0xFC) // lenght 6len = 6; else if (byte >= 0xF8)len = 5;else if (byte >= 0xF0)len = 4;else if (byte >= 0xE0)len = 3;else if (byte >= 0xC0)len = 2;elselen = 1;ch = input.substr(i, len);output.insert(ch);} return output.size();}這里我把字符串轉(zhuǎn)換為單字的集合(set)是由于應(yīng)用場(chǎng)景的須要,假設(shè)須要保持單字在字符串中的位置,能夠非常方便的用vector來(lái)替換set。
以下是獲取UTF-8字符串的字符個(gè)數(shù)(注意,不是字符串長(zhǎng)度哦)的代碼:
size_t get_utf8_length(const std::string &input) {size_t length = 0;for (size_t i = 0, len = 0; i != input.length(); i += len) {unsigned char byte = input[i];if (byte >= 0xFC) // lenght 6len = 6; else if (byte >= 0xF8)len = 5;else if (byte >= 0xF0)len = 4;else if (byte >= 0xE0)len = 3;else if (byte >= 0xC0)len = 2;elselen = 1;length ++;} return length;}轉(zhuǎn)載于:https://www.cnblogs.com/mengfanrong/p/3785791.html
總結(jié)
以上是生活随笔為你收集整理的UTF-8编码的字符串拆分成单字、获取UTF-8字符串的字符个数的代码及原理(c++实现)...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: linux下实现getch()函数的功能
- 下一篇: 转换到 COFF 期间失败: 文件无效或