Go hard or go home 要麼盡心盡力,要麼走人 No person has the right to rain on your dreams,you do it yourself. 沒有人有權利給你的夢想潑冷水,只有你本身給本身的夢想潑冷水node
看到這樣的文字是否是很勵志?那換一種方式你還會這樣想嗎? 16進製版:
複製代碼
476f2068617264206f7220676f20686f6d652089814e485168529b4ee58d742c89814e488d704eba20a4e6f20706572736f6e20206861732074686520726967687420746f207261696e206f6e20796f757220647265616d732c796f7520646f20697420796f757273656c662e206ca167094eba6709674352297ed94f60768468a660f36cfc51b76c342c53ea67094f6081ea5df17ed981ea5df1768468a660f36cfc51b76c34mongodb
然而他的字符編碼是GB2312的,叫我轉化成易懂的字符串,當時我就懵b了。由於當時我對字符編碼一竅不通,而後就網上,查啊查,最後終於想到了解決方案
複製代碼
字符是各類文字和符號的總稱,包括各個國家文字、標點符號、圖形符號、數字等。數據庫
字符集是多個字符的集合,字符集種類較多,每一個字符集包含的字符個數不一樣,常見字符集有:ASCII字符集、ISO 8859字符集、GB2312字符集、BIG5字符集、GB18030字符集、Unicode字符集等bash
一、 計算機要準確的處理各類字符集文字,須要進行字符編碼,以便計算機可以識別和存儲各類文字。 二、 字符編碼(encoding)和字符集不一樣。字符集只是字符的集合,不必定適合做網絡傳送、處理,有時須經編碼(encode)後才能應用。如Unicode可依不一樣須要以UTF-八、UTF-1六、UTF-32等方式編碼。 三、字符編碼就是以二進制的數字來對應字符集的字符。 所以,對字符進行編碼,是信息交流的技術基礎。服務器
一、使用哪些字符。也就是說哪些漢字,字母和符號會被收入標準中。所包含「字符」的集合就叫作「字符集」。 二、規定每一個「字符」分別用一個字節仍是多個字節存儲,用哪些字節來存儲,這個規定就叫作「編碼」。 三、各個國家和地區在制定編碼標準的時候,「字符的集合」和「編碼」通常都是同時制定的。所以,日常咱們所說的「字符集」,好比:GB2312, GBK, JIS 等,除了有「字符的集合」這層含義外,同時也包含了「編碼」的含義。 四、注意:Unicode字符集有多種編碼方式,如UTF-八、UTF-16等;ASCII只有一種;大多數MBCS(包括GB2312,GBK)也只有一種。網絡
一、在顯示器上看見的文字、圖片等信息在電腦裏面,其實並非咱們看見的樣子,即便你知道全部信息都存儲在硬盤裏,把它拆開也看不見裏面有任何東西,只有些盤片。假設,你用顯微鏡把盤片放大,會看見盤片表面凹凸不平,凸起的地方被磁化,凹的地方是沒有被磁化;凸起的地方表明數字1,凹的地方表明數字0。硬盤只能用0和1來表示全部文字、圖片等信息。 二、那麼字母」A」在硬盤上是如何存儲的呢?可能小張計算機存儲字母」A」是1100001,而小王存儲字母」A」是11000010,這樣雙方交換信息時就會誤解。好比小張把1100001發送給小王,小王並不認爲1100001是字母」A」,可能認爲這是字母」X」,因而小王在用記事本訪問存儲在硬盤上的1100001時,在屏幕上顯示的就是字母」X」。也就是說,小張和小王使用了不一樣的編碼表。小張用的編碼表是ASCII,ASCII編碼表把26個字母都一一的對應到2進制1和0上;小王用的編碼表多是EBCDIC,只不過EBCDIC編碼與ASCII編碼中的字母和01的對應關係不一樣。通常地說,開放的操做系統(LINUX 、WINDOWS等)採用ASCII 編碼,而大型主機系統(MVS 、OS/390等)採用EBCDIC 編碼。在發送數據給對方前,須要事先告知對方本身所使用的編碼,或者經過轉碼,使不一樣編碼方案的兩個系統可溝通自如。函數
一、不論是任何文字圖片等,最後都會以二進制的形式儲存到電腦的磁盤中(好比記事本A.txt,內容爲"ABC"文件,在此磁盤中表現的就是01 01這種二進制形式) 盤片表面凹凸不平,凸起的地方被磁化,凹的地方是沒有被磁化,凸起的地方表明數字1,凹的地方表明數字0。硬盤只能用0和1來表示全部文字、圖片等信息。是的 很強勢 二、 任何文件要儲存到電腦中,都會事先進行編碼,而後儲存到電腦的磁盤中,好比A.txt文件,默認編碼爲ANSI編碼,也能夠編碼爲UTF-8,然而不一樣的編碼方式 對應着計算機用一個字節仍是多個字節存儲,用哪些字節來存儲。 三、在雙方數據進行通信時,要麼就保證發送方和接受方的數據編碼是相同,要麼就是其中一方須要轉碼ui
字節byte和位bit是電腦裏的數據量單位。 1.按計算機中的規定,一個英文的字符佔用一個字節,而一個漢字以及漢字的標點符號、字符都佔用兩個字節。 2.1個字節等於8位 1byte=8bit 3.1bit在磁盤中以二進制01的形式保存 凸起的地方表明數字1,凹的地方表明數字0編碼
ASCII碼是西歐編碼的方式,採起7位編碼,因此是2^7=128,共能夠表示128個字符,包括34個字符,(如換行LF,回車CR等),其他94位爲英文字母和標點符號及運算符號等。spa
重點:
字符集:從符號(NUL="/0"=「空操做字符」)到「Z」再到「DEL」符號 字符編碼範圍:二進制:00000000——01111111 十進制:0-127 佔用字節:1字節 8bit 盤片儲存方式:凹凹凹凹凹凹凹凹——凸凸凸凸凸凸凸凸
注:NUL:‘\0'是一個ASCII碼爲0的字符,從ASCII碼錶中能夠看到ASCII碼爲0的字符是「空操做字符」,它不引發任何控制動做,也不是一個可顯示的字符。
但咱們發現ASCII碼是沒有中文編碼的,顯然在天朝是不夠用的,因而GB2312誕生了。 ###GB2321 GB2312 是對 ASCII 的中文擴展。兼容ASCII。
編碼規定: 編碼小於127的字符與ASCII編碼相同, 特性:兩個大於127的字符連在一塊兒時,就表示一個漢字,前面的一個字節(稱之爲高字節)從0xA1用到0xF7,後面一個字節(低字節)從0xA1到0xFE,這樣咱們就能夠組合出大約7000多個簡體漢字了。
字符集:從符號(NUL="/0"=「空操做字符」)到「Z」到「齇"(簡體中文) 字符編碼範圍:16進制:0x0000-(中間有一部分是未使用的)-0xF7FE 佔用字節:英文 1字節 8bit 盤片儲存方式:凹凹凹凹凹凹凹凹——凸凸凸凸凸凸凸凸 中文 2字節 16bit 凹凹凹凹凹凹凹凹凹凹凹凹凹凹凹凹——...
GBK 兼容ASCLL 兼容 GB2312 是GB2312的擴展 可是中國的漢字太多了,咱們很快就就發現有許多人的人名沒有辦法在這裏打出來,不得不繼續把 GB2312 沒有用到的碼位找出來用上。後來仍是不夠用,因而乾脆再也不要求低字節必定是127號以後的內碼,只要第一個字節是大於127就固定表示這是一個漢字的開始,無論後面跟的是否是擴展字符集裏的內容。結果擴展以後的編碼方案被稱爲 「GBK」 標準,GBK 包括了 GB2312 的全部內容,同時又增長了近20000個新的漢字(包括繁體字)和符號。 ###Unicode Unicode是國際組織制定的能夠容納世界上全部文字和符號的字符編碼方案。 目前的Unicode字符分爲17組編排,0x0000至0x10FFFF,每組稱爲平面(Plane),而每平面擁有65536個碼位,共1114112個。然而目前只用了少數平面。UTF-八、UTF-1六、UTF-32都是將數字轉換到程序數據的編碼方案。
UTF-8以字節爲單位對Unicode進行編碼。從Unicode到UTF-8的編碼方式以下: UTF-8的特色是對不一樣範圍的字符使用不一樣長度的編碼。對於0x00-0x7F之間的字符,UTF-8編碼與ASCII編碼徹底相同。UTF-8編碼的最大長度是6個字節。從上表能夠看出,6字節模板有31個x,便可以容納31位二進制數字。Unicode的最大碼位0x7FFFFFFF也只有31位。 例1:「漢」字的Unicode編碼是0x6C49。0x6C49在0x0800-0xFFFF之間,使用用3字節模板了:1110xxxx 10xxxxxx 10xxxxxx。將0x6C49寫成二進制是:0110 1100 0100 1001, 用這個比特流依次代替模板中的x,獲得:11100110 10110001 10001001,即E6 B1 89。 舉一個例子:It's 知乎日報
你看到的unicode字符集是這樣的編碼表:
I 0049 t 0074 ' 0027 s 0073 0020 知 77e5 乎 4e4e 日 65e5 報 62a5 每個字符對應一個十六進制數字。
計算機只懂二進制,所以,嚴格按照unicode的方式(UCS-2),應該這樣存儲:
I 00000000 01001001 t 00000000 01110100 ' 00000000 00100111 s 00000000 01110011 00000000 00100000 知 01110111 11100101 乎 01001110 01001110 日 01100101 11100101 報 01100010 10100101 這個字符串總共佔用了18個字節,可是對比中英文的二進制碼,能夠發現,英文前9位都是0!浪費啊,浪費硬盤,浪費流量。
怎麼辦?
UTF
UTF-8是這樣作的:
- 單字節的字符,字節的第一位設爲0,對於英語文本,UTF-8碼只佔用一個字節,和ASCII碼徹底相同;
這樣就造成了以下的UTF-8標記位:
高位字節 | 低位字節 | 低位字節 | 低位字節 | 低位字節 | 低位字節 |
---|---|---|---|---|---|
0xxxxxxx | |||||
110xxxxx | 10xxxxxx | ||||
1110xxxx | 10xxxxxx | 10xxxxxx | |||
11110xxx | 10xxxxxx | 10xxxxxx | 10xxxxxx | ||
111110xx | 10xxxxxx | 10xxxxxx | 10xxxxxx | 10xxxxxx | |
1111110x | 10xxxxxx | 10xxxxxx | 10xxxxxx | 10xxxxxx | 10xxxxxx |
... .... |
1.從這個能夠看出,一樣的字符集,但unicode編碼和gbk編碼是不一樣的。,因此unicode字符集不兼容gbk字符集 2.只要知道unicode字符集的編碼表,就能夠用UTF8編碼規則找到UTF-8對應的漢字編碼
從上面的內容瞭解了字符編碼之後,之後遇到相關的字符編碼問題的時候至少有解決的思路,而不是一頭霧水
NodeJS服務端環境下 476f2068617264206f7220676f20686f6d652089814e485168529b4ee58d742c89814e488d704eba20a4e6f20706572736f6e20206861732074686520726967687420746f207261696e206f6e20796f757220647265616d732c796f7520646f20697420796f757273656c662e206ca167094eba6709674352297ed94f60768468a660f36cfc51b76c342c53ea67094f6081ea5df17ed981ea5df1768468a660f36cfc51b76c34 容易產生誤區: 這個問題的狀況並非字符亂碼問題,而只是怎樣解析16進制gb2312字符,只是利用了字符編碼的原理。 1.我接受的是gb2312格式的數據,可是這裏並無亂碼,由於服務器發過來的是數字和英文,gb2312是兼容ASCII的。 2.我設置了(接受響應數據編碼格式)response.setEncoding('gb2312');即便我不設置響應格式,nodejs默認識utf-8的,utf-8和gbk都是兼容ASCII,也是就是支持英文和數字
var http=require('http');
var Iconv = require('iconv-lite');//轉碼數據
var GetHttp=function(options,callback){
var AllData="";
try{
var GetReq = http.request(options, function (res) {
console.log('STATUS: ' + res.statusCode);
res.setEncoding('gb2312');
if(res.statusCode==200){
res.on('data', function (chunk) { AllData+=chunk;})
.on('end',function(){callback(200,AllData);})
}else{
callback(500,'error');
}
console.log(AllData);
});
GetReq.on('error',function(err){callback(500,err)});
GetReq.end();
}catch(error){
callback(500,error);
}
}
exports.GetHttp=GetHttp;
複製代碼
開始問題分析: 1.字符集分析:gb2312支持數字和英文和6000+漢字 2.編碼分析:英文佔一個字節,中文佔兩個字節(這就是問題)
//1.fromCharCode() 可接受一個指定的 Unicode 值,而後返回一個字符串。但咱們的數據是gb2312的編碼數據,然而gbk和unicode的編碼方式又不同,因此解析出來的數據會亂碼
//2.利用下面的代碼,中文也會亂碼,由於英文佔1個字節,中文佔2個字節,1個字節是8個二進制流的bit=2個16進制流的bit,而中文=4個16進制流的bit,下面的代碼至關於把1個16進制的數轉爲字符
function HexTostring(s) {
var r = "";
for (var i = 0; i < s.length; i += 2) { var sxx = parseInt(s.substring(i, i + 2), 16); r += String.fromCharCode(sxx); }
return r;
}
複製代碼
這時就要想到,中文漢子對照表:
首先把漢子編碼對照表存入以存入數據庫(mongodb)
獲取,並以key=gbk16進制編碼 value=漢子的形式存下來
var dicUniCodeCN=new Array();
DBTool.FindData('mongodb://數據庫地址/數據庫名','unicodeCN',{},function(Docs){
if (Docs.length>0) {
for (var i = 0; i < Docs.length; i++) {
dicUniCodeCN[Docs[i].gbk16.toString().toUpperCase()]=Docs[i].CN;
};
}
});
複製代碼
3.特性:gb2312的高位字節若是大於127(ASCII),就爲中文,只有gb2312具備這個特性
var simpleCNStr="";
for (var j = 0; j < hexData.length; j += 2){
//高位字節>127爲中文
var strHex=hexData.substring(j,j+2);
console.log(parseInt("0x"+strHex,16));
if (parseInt("0x"+strHex,16)>127) {
strHex=hexData.substring(j,j+4);
j+=2;
simpleCNStr+=dicUniCodeCN[strHex];
}else{
simpleCNStr+=String.fromCharCode(parseInt(strHex,16));
}
}
複製代碼
4.若是想兼容utf-8和unicode和gbk,那麼能夠4位16進制的字符截取,若是大於127,那麼默認爲中文,不然就是英文或字符或數字
var simpleCNStr="";
for (var j = 0; j < hexData.length; j += 4){
//4位截取,大於127的爲中文
var strHex=hexData.substring(j,j+4);
console.log(parseInt("0x"+strHex,16));
if (parseInt("0x"+strHex,16)>127) {
//不想寫了
}else{
//待續 大家寫吧...
}
}
複製代碼
parseInt("10"); //返回 10
parseInt("19",10); //返回 19 (10+9)
parseInt("11",2); //返回 3 (2+1)
parseInt("17",8); //返回 15 (8+7)
parseInt("1f",16); //返回 31 (16+15)
parseInt("010"); //未定:返回 10 或 8
複製代碼
這個函數是把數字或進制字符都轉爲10進制的數字,第二個參數radix表示的是第一個參數string的類型(10進制,2進制,8進制,16進制),我以前很白菜的理解爲我想把第一個參數string轉化成16進制。哎,我仍是太年輕啊