中文編碼是乙個複雜而繁瑣的問題,尤其是在使用c++的時候,不像python這種直接就可以迭代出單個中文字元,c++中是以位元組為單位的,那麼我們要讀取乙個中文字元就要讀取三次位元組流,讀取英文本元就只需要讀取一次,是不是超級麻煩。那麼c++怎麼樣在中英文混合的字串中分離中英文或者計算字串長度(不是位元組數)呢,那就需要徹底搞清楚編碼是個怎麼回事。
ascii 碼
,全稱 american standard code for information interchange,一共規定了 128 個字元的編碼,包括 10 個阿拉伯數字(從0x30
開始,使用16進製表示)、26 個大寫字母(從65
開始)、26 個小寫字母(從97
開始),33 個英文標點符號,及 32 個控制字元,還有最後乙個0x7f
。
128 個字元,至少需要 7 個位元(bit)來表示,而乙個位元組(byte)有 8 個位元,故將位元組的最高位的位元規定為 0(這是規定),使用剩下的 7 個位元,剛好可以完整的表示 ascii 碼規定的字元。
阿拉伯數字的編碼從0x30
到0x39
,按順序分別表示 0 到 9 這 10 個字元。這樣帶來了乙個優勢:可以直接做字元的減法,得到字元對應的數字大小。大寫字母和小寫字母亦是如此。舉個例子:
char ch_9 = '9';
int value = ch_9 - '0';
assert(value == 9);
大寫字母從0x41
開始(二進位制表示1000001
),小寫字母從0x61
(二進位制表示1100001
)開始。注意觀察,二者相差了乙個0x20
,即 32。任意乙個小寫字母對比對應的大寫字母,僅第 6 個比特有 1 與 0 的不同。進而可以通過這一點進行大小寫字母的判斷及其轉換。
//判斷字母大小寫
char a = 'b';
if ((a & 0x20) == 0x20)
//小寫轉大寫
char a = 'b';
char c = a ^ 0x20;
cout << c << endl;
//輸出 b
//大寫轉小寫
char a = 'b';
char c = a | 0x20;
cout << c << endl;
//輸出 b
//當然直接加上或者減去 32 也是可以實現大小寫轉換的
ascii 中的控制字元較為少用,有印象的僅僅是bell
字元(0x07
)。大一學習程式設計的時候發現可以通過printf("a");
使用電腦發出蜂鳴聲,如今在 mac 上嘗試依然有效。
ascii 碼僅規定了 128 個字元,只能滿足英文的基本需求。乙個位元組最多能表示 256 個字元,而中文的常用漢字就有數千了,故而需要使用多個位元組來表示漢字。兩個位元組可以表示的字元上限為 65536,絕大部分情況下能夠滿足漢字使用的需求了。經典的漢字編碼包括gbk、gb2312、gb18030、cp939
等。
在漢字編碼中,之前 ascii 碼沒有使用的最高位派上了用場。如果乙個位元組最高位是 0,說明這個位元組便是 ascii 碼,查表解析即可;如果最高位非 0,那麼說明這是乙個多位元組編碼,需要聯合下乙個位元組一起進行解析。
unicode 便是便是文字和符號的統一度量衡。unicode,unique code,universe code,全世界每乙個字元對應乙個唯一的編碼。unicode 收錄了大量的漢字,漢字的編碼從0x4e00
開始,到0x9fff
結束。
然而 unicode 僅僅定義了符號與二進位制編碼的關係,但沒有定義如何儲存和解析這些二進位制編碼。如果直接將二進位制編碼寫入檔案,那麼讀取時會產生歧義。例如4e 00 41
,你無法知道這記錄的是 1 個字元,還是 2 個字元(可以解碼為「一a」),或者是 3 個字元(可以解碼為「n[空]a」)。如果統一每個字元的記錄長度,那麼對於常用中文便需要至少 3 個位元組來表示乙個符號,那麼對於全英的檔案則太浪費了。
unicode 解決了編碼統一的問題,但沒有解決編碼儲存和解析的問題。utf
-8 則解決了 unicode 沒有解決的問題。
utf-8
對於原有的 ascii 碼完全相容,而最高位的 1 的數量表示當前字元占用的位元組數。可以通過上表將 unicode 轉換為utf-8
編碼,即將 x 按照高低位順序替換為 unicode 的二進位制位,缺了則使用 0 補齊。以漢字「一」為例,其 unicode 編碼為0x4e00
,對應的二進位制為100 1110 0000 0000
,二進位制共計 15 位。填充到1110***x 10****** 10******
中(從右往左依次替換掉x,因為有16個x,所有最左邊的乙個x用0代替),最高位缺了一位,使用 0 補齊,最終可得11100100 10111000 10000000
,即e4 b8 80
。使用一行python3
**驗證一下:
print(b'xe4xb8x80'.decode())
# 列印結果:一
utf-8
編碼還保持著乙個優秀的特性,無論是使用左對齊(字串排序),還是右對齊(數值排序),utf-8
編碼始終保持著與 unicode 一致的大小順序。舉個栗子 ,字串u8"a" < u8"一&
quot;, 同時寬字元wchar_t(l'a') < wchar_t(l'一')
。仔細想想還是蠻有意思的。
//使用c++實現像python一樣的字串遍歷
std::vector spliteachchar(const string chars)
else if ((input[i] & 0xe0) == 0xc0) else if ((input[i] & 0xf0) == 0xe0) else if ((input[i] & 0xf8) == 0xf0)
words.push_back(input.substr(i, next));
i += next;
}return words;
}
linux使用iconv在不同字元編碼中轉換
在linux系統下利用iconv命令進行gbk與utf 8字元編碼間的轉換 gbk編碼和utf 8編碼的區別 1.gbk的文字編碼是雙位元組來表示的,即不論中 英文本元均使用雙位元組來表示,只不過為區分中文,將其兩個位元組的最高位都定成1。utf 8編碼則是用以解決國際上字元的一種多位元組編碼,它對...
C 中判斷字元是否大寫
在c 中,通常判斷乙個字元是否為大寫字母,有些人可能會第一時間想到用正規表示式,那除了正規表示式,是否還有其他方式呢?答案是肯定的,先一睹為快,具體 如下 using system using system.collections.generic using system.linq using sy...
Python 中的字元編碼
1 str型別可以理解為乙個二進位制block,或multibyte 2 multibyte str.decode unicode 3 unicode str.encode multibyte str binary block 4 unicode str 的操作引數也應為unicode,如 unic...