你需要知道的編碼 亂碼 知識

2022-07-21 00:51:17 字數 4740 閱讀 7343

中文在風靡全球的路上如果一定有阻礙,那就是亂碼啊。引無數大神盡折腰的編碼轉換問題,這篇文章就記錄下這個問題。

大家知道,計算機是只認識二進位制的,如果乙個字元變成了我們肉眼可見的亂碼時,一定是因為我們給了計算機錯誤的編碼格式導致的。

文章開始,我們先說說程式設計時,我們的儲存**的檔案的編碼,以vs2008為例,在中文作業系統下,我們的程式設計檔案會被儲存為gb2312編碼,但凡檔案中使用了中文,為了正常顯示中文,我們必須使用擴充套件的編碼方式來顯示這個檔案。gb2312算是最早的中文編碼方式了,後面依次出了gbk和gb18030,這些暫且不提,

編碼參考可以看這裡

。gb2312使用兩個位元組表示乙個中文字元,而utf-8則使用3個位元組表示乙個中文。如果不想看文獻,我們可以走乙個實驗:

#include //

this file for coder test

#include

using

std::cout ;

using std::string

;int

main()

分別把以上**,以gb2312和utf-8儲存後,生成的結果分別為:

english lenght:4

chinese lenght:8

english lenght:4

chinese lenght:12

以上結果很清楚的證明了以上說法。當然了,英文本元是編碼界的一等公民的,所以編碼方式變化基本不會影響**最後的結果。而對於中文,我們就很尷尬了,畢竟string的length函式不可用的情況下,對應的c語言裡的strlen函式也是不準確的。這個問題 ,我們在後面說說如何解決。現在,我們還是說回檔案的編碼問題,因為windows的文字檔案換行格式與linux不同的原因,windows行尾使用\r\n來換行,linux行尾使用\n來換行,\r在linux就會顯示成奇怪的符號。這樣的系統級的差異,我們不會擴充套件,只以windows系統說明後面的問題。

不同的檔案編碼在轉換時,必然會引起亂碼問題,這裡的亂碼是因為錯誤的字元對映關係導致的。類似的說明網文也是很多的。

這裡只說明一點,為使計算機支援更多語言,相容ascii碼表,在0x00~0x7f之間的字元,依舊是1個位元組代表1個字元。通常使用 0x80~0xff 範圍的 2 個位元組來表示 1 個非英語字元。像gb2312, big5, jis 等使用ansi碼表的0x80~0xff範圍的 2 個位元組來代表乙個字元的各種漢字延伸編碼方式,統稱為ansi 編碼。因此,在簡體中文系統中,ansi編碼實際上是指gbk(gb2312或者gb18030).

開發者除了需要處理檔案的編碼導致的亂碼外,還需要處理編碼過程中,網路傳輸時的亂碼問題。

在開發過程中,我們經常遇到tchar來表示乙個字元位元組,眾所周知的原因,這裡其實隱藏了char和wchar_t型別,即所謂的窄位元組 和 寬位元組,乙個char對應1個8bit,而wchar_t又存在平台差異,windows下是2個8bits,對應乙個utf-16編碼字元(linux下是4個8bit,對應乙個utf-32字元),windows下的wchar_t定義為

typedef unsigned short wchar_t; /* 16 bits */在編碼時,我們使用l來表示我們使用的是unicode編碼,但是wchar_t也可以儲存其他編碼的字元,即如果我們不加l標識的話,這個字元就是我們的程式設計檔案的編碼格式,但是在linux下我們無法使用不加l的字串給wchar_t型別賦值了。來,show me the code:

wchar_t width_t1 = '中'

; wchar_t width_t2 = l'中'

; printf(

"%0x %0x\n

",width_t1,width_t2);

檔案編碼為gb2312時的輸出

d6d0 4e2d
檔案編碼為utf-8時的輸出

e4b8ad 4e2d
由此可見,當使用l修飾的中文後, 因為它已經表明使用了特定的編碼方式,所以它在記憶體中的數值是一致的,不會隨著檔案的編碼而改變,但是不加入l則就與檔案的編碼格式相關了。

現在,我們已經積累了2個隨著檔案編碼方式不同,導致程式輸出不同的問題了,這些都是亂碼的根源。

為了弄清楚亂碼的問題,我們從

檔案的編碼

方式,程式設計方式

來說明了潛在的問題,現在,我們來看看可以從哪些方面解決這個問題。

為了正常顯示中文,我們可以將檔案編碼設定為gb2312的,但是現在很多ide把字元編碼預設為utf-8了比如qt的ide ,qtcreator。如前所述,utf-8儲存中文時占用的磁碟空間比gb2312更大些,嗯,其實吧,儲存空間並不是什麼大問題。不同的檔案編碼其實影響的是我們在做網路資料的傳輸,我們需要根據不同的編碼來轉碼為utf-8了。

備註說明下:在linux下,含中文的檔案最好儲存為utf-8格式的,使用ansi編碼在編輯時可能會報"converting to execution character set: invalid or incomplete multibyte or wide character";這需要做很多額外的工作來消除。

現在,我們假設,檔案的編碼格式為gb2312,而我們需要使用中文字串了,使用string char等型別來儲存中文字元是完全可以的,那麼這裡就會涉及到1個中文2個char位元組的口訣了,古時候(嗯,那時候),即時現在,很多人都還沒玩壞這個口訣。這自然不是武功秘籍,所以,我們需要改變下編碼思路,因為,直接使用string儲存中文,字元長度等函式都是不準確的。於是,我們使用了嚴格的寬位元組來規避這些問題,vs中可以把字元設定為unicode,這個設定不是為檔案編碼準備的,是為程式設計中的編碼準備的。設定完畢後,我們將合理的使用tchat等字元型別。當字元設定為unicode後,這裡的tchar會被解析為wchar_t,個人其實並不喜歡微軟的字元封裝,所以更喜歡直接使用c++標準庫中的wchar_t及其標準操作函式。show me the code:

wchar_t width_t1 = "

中文1測試起來

"; //

error c2440: 「初始化」: 無法從「const char[14]」轉換為「wchar_t 」

以上**說明,vs下沒有加l的中文串預設為chat型別,

wchar_t width_t2 = l"

中文2測試起來";

printf(

"%s \n

",width_t2);

結果(powershell下顯示)

-n噀2
又見亂碼,喜不勝收啊,分析下,加了l後,我們的wchar中加入的為utf-16的字元編碼,而我們的顯示介面為powershell的字符集為gbk的,把utf-16的字元解析為gbk自然就是亂碼了。於是,就涉及到解碼了,這裡,我們的目標就是把wchar_t型別的字元轉為ansi編碼,如果不知道為什麼是這樣的轉換,可以多檢視資料,其實,本文前面也略有提及,具體的轉換在下節。

wstring wchar1(l"

this");

wstring wchar2(l

"只有中文");

wstring wchar3(l

"中e混合");

std::cout

<< "

e文長度 :

"<< wchar1.length()<<:endl>

std::cout

<< "

中文長度 :

"<< wchar2.length()<<:endl>

std::cout

<< "

混合長度 :

"<< wchar3.length()

中文長度 :4

混合長度 :4

可見,在寬位元組加持下,中英文的長度等總算統一了,所有的字元都是按乙個計算,讓乙個中文是兩個英文本元見鬼去吧,我們完全不需要關係在磁碟或者記憶體中字元的儲存方式,因為我們更關心程式設計的字串本身。

在windows下,編碼轉換主要是widechartomultibyte和multibytetowidechar函式

在此之前,我們先來了解下**頁的概念,

參考這裡

,知道了codepage的存在,我們就很好理解這兩個函式了,這兩個函式就是在查表,找到寬位元組 到 多位元組(ansi)的對應關係;

show me the code

//

函式名中的unicode實際就是utf-16,

//需要加標頭檔案 windows.h

char * unicodetoansi(const wchar *lpszstr)

return

lpansi;

}char * charansi =unicodetoansi(width_t2);

printf(

"%s \n

",charansi);

delete charansi;

執行後ok,這一次總算顯示正常了。

以上,告訴了你從wchar_t向ansi轉換的過程,那麼同理,你可以寫出其他的轉換函式了,只是,知道為什麼要轉其實比知道怎麼轉更重要。

同樣的道理,在聯網通訊時,為了讓對方正確識別,我們需要把字元全部轉成utf-8,

前文說過,我們需要使用寬位元組來使用中文字串,所以,這裡我們只需要把寬位元組的utf-16轉換為utf-8即可。只有英文的可以不做轉換。

另外,本地化程式設計也是乙個大坑,以後繼續再填吧。

Sybase IQ,你需要知道的基礎

sybase iq,你需要知道的基礎 第一,知道iq跟其它的關係型資料庫相比,它的主要特徵是什麼?包括查詢快 資料壓縮比高 load快,但是插入更新慢,不太適合資料老是變化,它是按列儲存的。這時候你就知道它適做dss 決策支援系統 資料集市,資料倉儲,它不適合oltp。適合olap。第二,知道iq自...

Sybase IQ,你需要知道的基礎

sybase iq,你需要知道的基礎 第一,知道iq跟其它的關係型資料庫相比,它的主要特徵是什麼?包括查詢快 資料壓縮比高 load快,但是插入更新慢,不太適合資料老是變化,它是按列儲存的。這時候你就知道它適做dss 決策支援系統 資料集市,資料倉儲,它不適合oltp。適合olap。第二,知道iq自...

關於快取你需要知道的

作後端開發的同學,快取是必備技能。這是你不需要花費太多的精力就能顯著提公升服務效能的靈丹妙藥。前提是你得知道如何使用它,這樣才能夠最大限度發揮它的功效,並抑制其 本文將介紹最如何正確的新增和更新快取。這部分將介紹在開始加快取之前我們必須要做的事情。這步非常重要,如果沒弄好,很有可能加了快取反而不如不...