Javascript 的中文編碼是使用兩個 bytes 來儲存的,而英文、符號等是使用一個 byte 來儲存。
Using length
使用 string.length 來計算長度時,中文字串會被當成是一個字來計算,因為 Javascript 是使用 multiple byte 計算,就像是 php 的 mb_strlen。
Examplevartx="測試&eng";
alert(tx.length);
//output: 6
看到吧不管是中文,英文,都當成一個字來算,所以總共是 6 個字,不過有時候我們並不想把中文字當成一個字來計算,因為中文字明明佔的 byte 數就是比較多,所以來看一下中文編碼吧。
中文編碼
一般使用 big5 為繁體中文編碼,每一個中文字是使用兩個 bytes 來儲存。
UTF-8 編碼則是每一個中文字使用三個 bytes 來儲存。
不過這個算法對 javascript 的中文長度計算是有問題的,首先我寫了一小段 Javascript 程式碼,以及兩個不同編碼的網頁,我先抓取一段 UTF-8編碼的網頁,然後計算他的長度。utf8_data.txt 的內容 = [測試中文eng] ,這個檔案在 linux 系統中看到的檔案大小為 15 bytes,代表一個中文字使用三個 bytes 儲存,不過在 Javascript中抓到的字串長度 = 7。big5_data.txt 的內容 = [測試中文eng],這個檔案在 linux 系統中看到的檔案大小為 11 bytes,代表一個中文字使用二個 bytes 儲存,不過在 Javascript中抓到的字串長度 = 9
View Demo
Examplefor(vari=0;i
c+=""+tx.charCodeAt(i).toString(2)+"
";
k+=""+tx.charCodeAt(i).toString()+"
";
}
document.body.innerHTML+=c;
document.body.innerHTML+=k;
//output
/*
110111000101100
1000101001100110
100111000101101
110010110000111
28204
35430
20013
25991
*/
從上面就可以看出來,雖然我是使用 UTF-8 編碼,不過轉成二進位後,每個中文字都是兩個 bytes 的長度而已(從上面的二進位數字中來看,最多只有 16 個 「0和1」,而一個 byte 有 8 個 bits ,所以是 兩個 bytes)。
計算文字 bytes 數
我將每一個文字轉成數字,再去計算他的二進位的 bit 數,決定文字是使用幾個 byte 來儲存。
兩個不同的編碼頁面,使用 length抓到的結果是不相同的,原因是我寫的 Javascript 是使用 UTF-8 編碼,所以可以正常的計算 UTF-8編碼的內容長度,不過在計算 big5 編碼的內容時,就會因為編碼表的不同,而出現怪怪的結果。
接著我試著在 Javascript 中,把中文字轉成二進位的編碼來看看。
Examplevartx="測試中文";
varc=""
functionstringBytes(c){
varn=c.length,s;
varlen=0;
for(vari=0;i
s=c.charCodeAt(i);
while(s>0){
len++;
s=s>>8;
}
}
returnlen;
}
vartx="測試中文12313";
$(document.body).append(stringBytes(tx));
//output: 13
上個範例中,中文字有四個,數字有五個,每個中文字為 2 bytes ,所以總合長度是 13 bytes 。
不存在三個 bytes 的文字
測試了一下 Javascript 是否有三個 bytes 的文字,結果發現,當編碼的數字大於 65535 時(16 bits),數字又會回到 0 開始計算,所以 Javascript 的編碼表中最多只有 65536 個文字 (包含 0 , 0 ~ 65535)。
Examplevart1=String.fromCharCode(65586);
vart2=String.fromCharCode(50);
if(t1==t2)alert("yes")
//兩個文字都是 2 , (65586 -65536 =50) http://www.puritys.me/docs-blog/article-32 : 這裡可以輸出 HTML 編碼表, 從數字 19968 後開始,就是中文字的編碼表。
Using encodeURIComponent
另一種計算方式是使用 encodeURIComponent ,先使用 encodeURIComponent 將字串進行編碼,之後再用 Regular Expression 計算 bytes 數。
Exampletx="測式中文xxxx";
varstr=encodeURIComponent(tx);
console.log("utf8:"+str);
len=str.replace(/%[A-F\d]{2}/g,'U').length;
console.log("len = "+len);
這個方式可以成功的計算 Big5 & UTF-8 的編碼長度。
get string length from web
如果我們使用 ajax 去抓網頁的資料時, Big5 編碼的頁面會自動被轉換成 UTF-8 的亂碼,這時 encodeURIComponent 就沒辦法計算正確的長度。
用 ajax 從 header 中抓頁面的長度
如果是要抓頁面的size ,可以直接從 header 的資訊中取得,方式如下。
Example//using jquery
vargeturl;
geturl=$.ajax({
type:"get",
url:"b.txt",
beforeSend:function(){
},
success:function(tx){
varheader=geturl.getAllResponseHeaders();
varre=/Content-Length:[\s]([0-9]+)/;
vark=header.match(re);
document.body.innerHTML="length = "+k[1];
}
});
使用 ajax 取得 header 的內容
在 Ajax 回傳的 物件中,使用 method : getAllResponseHeaders,就可以抓到 response header 的內容,範例如下。
Examplevarrequest=null;
try{
request=newXMLHttpRequest();
}catch(trymicrosoft){
try{
request=newActiveXObject("Msxml2.XMLHTTP");
}catch(othermicrosoft){
try{
request=newActiveXObject("Microsoft.XMLHTTP");
}catch(failed){
request=null;
}
}
}
functionajaxResultHeader(){
if(request.readyState==4){
if(request.status==200){
vartx=request.responseText;
varheader=request.getAllResponseHeaders();
console.log("header = "+header);
}else
alert("Error! Request status is "+request.status);
}
}
functionajaxGetHeader(){
varurl="b.txt";
request.open("GET",url,true);
request.onreadystatechange=ajaxResultHeader;
request.setRequestHeader("Content-Type","application/octet-stream");
request.send();
}
ajaxGetHeader();
取得的 header 內容
ExampleDate: Wed, 29 Feb 2012 03:01:23 GMT
Server: Apache/2.2.14 (Win32) DAV/2 mod_ssl/2.2.14 OpenSSL/0.9.8l mod_autoindex_color PHP/5.3.1 mod_apreq2-20090110/2.7.1 mod_perl/2.0.4 Perl/v5.10.1
Last-Modified: Wed, 29 Feb 2012 02:44:38 GMT
Etag: "b00000002859d-827-4ba115319353b"
Accept-Ranges: bytes
Content-Length: 2087
Content-Type: text/plain
使用 ajax 從 content 中取得前 2KB 的Bytes 數
HTTP Request 中本身有個屬性 Range , 可以指定我要取得多少 bytes ,從 x1 ~ x2 bytes ,因為從 Server 端取得的資料就是 2 KB ,這樣就不需要經過 Ajax 的胡亂編碼過程,就能正確的取得bytes數,用法就是在 Request Header 中加入 Range:bytes=0-2000,下面是範例。 ! 使用 Range 抓取片段資料,Http Response 的 status 會等於 206
Examplevarrequest=null;
try{
request=newXMLHttpRequest();
}catch(trymicrosoft){
try{
request=newActiveXObject("Msxml2.XMLHTTP");
}catch(othermicrosoft){
try{
request=newActiveXObject("Microsoft.XMLHTTP");
}catch(failed){
request=null;
}
}
}
functionajaxResult(){
if(request.readyState==4){
if(request.status==200||request.status==206){
vartx=request.responseText;
console.log("content= "+tx);
}else
alert("Error! Request status is "+request.status);
}
}
functionajaxGet(){
varurl="b.txt";
request.open("GET",url,true);
request.onreadystatechange=ajaxResult;
request.setRequestHeader("Content-Type","application/octet-stream");
request.setRequestHeader("Range","bytes=0-2000");
request.send();
}
ajaxGet();
Request Header Example
線上測試,使用 Ajax 抓 page header And content線上測試
HeaderContent
Bytes: from ~Request 測試
備註
bit 運算
在電腦的世界中,數字都是使用二進位來計算的,下面是基本的十進位與二進位對照表。
十進位二進位
210
4100
81000
6110
二進位運算符號 「>>」,「 >> 1」這個是指二進位的數字向右邊移動一格,所以最右邊的數字會被刪除,範例如下。
十進位運算二進位的原始值二進位結果
2 >> 1 = 1101
11 >> 2 = 3111011
8 >> 1 = 41000100
6 >> 1 = 311011