基於JavaScript的Base64編碼、解碼算法

    Base64編碼是一種很經常使用的編碼,在RSA、AES等加密算法中,密鑰對的表示一般使用Base64,UTF-7也是在Base64的基礎上變化而來,固然全部僅支持ASCII碼傳輸的網關在傳輸非ASCII碼時,均可以使用Base64編碼。javascript

    Base64編碼的方法很是簡單,將3個Byte共24Bit從高到低從新拆分紅4部分每部分6Bit,分別爲0x0~0x3f,對應字符爲A~Z和a~z和0-9和+/,共64個。若是最後剩餘1個Byte,則將其編碼爲2個6Bit的Base64編碼(第二個Base64編碼僅2Bit,需在其後面添加4Bit的0),再在末尾添加2個=字符;若是最後剩餘2個Byte,則將其編碼爲3個6Bit的Base64編碼(第三個Base64編碼僅4Bit,需在其後面添加2Bit的0),再在末尾添加1個=字符。css

    Base64解碼的方法與編碼相反,將4個Base64編碼字符轉換爲對應的0x0~0x3f,共24Bit,而後從新拆分紅3部分,每部分8Bit,即1Byte,若末尾有=字符,則按編碼方法中描述的規則反向處理。html

    網上有不少現成的算法,但彷佛沒有使用JavaScript實現的,實際上使用JavaScript實現也不是太複雜。去年我就寫了這個程序,只是忘記放在這裏了,前天給學生講課(放假前的最後一課,開學就大四了,可編程的能力尚需錘鍊),講到了這個,特地加了不少註釋,放在這裏,以饗讀者。java

    一共寫了兩個版本,其編碼、解碼的時間複雜度均爲O(n),但版本二使用了一些技巧,使得其效率更高,編碼效率約是版本一的3倍,解碼效率約是版本一的4倍,同時編碼、解碼循環內少了一個判斷。算法

    版本一:編程

  
  
  
  
  1. <html xmlns="http://www.w3.org/1999/xhtml"> 
  2. <head> 
  3. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
  4. <title>Base64編碼、解碼算法 - 夢遼軟件工做室</title> 
  5. <style type="text/css"> 
  6.     body,table {  
  7.         font-family:宋體;  
  8.         font-size:9pt;  
  9.     }  
  10.     input {  
  11.         width:200px;  
  12.         height:25px;  
  13.     }  
  14. </style> 
  15. </head> 
  16. <body> 
  17. <script type="text/javascript"> 
  18. /*  
  19. Base64編碼規則:  
  20. 一、將三個byte的數據,前後放入一個24bit的緩衝區中,先來的byte佔高位;  
  21. 二、數據不足3byte的話,緩衝區中剩下的bit用0補足;  
  22. 三、而後,每次取出6個bit(由於2^6=64,即0到63),按照其值選擇ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/中的字符做爲編碼後的輸出;  
  23. 四、不斷進行,直到所有輸入數據轉換完成;  
  24. 五、若是最後剩下兩個輸入數據,在編碼結果後加1個=;若是最後剩下一個輸入數據,編碼結果後加2個=;若是沒有剩下任何數據,則什麼都不加,這樣能夠保證數據還原的正確性。  
  25. 注1:先對輸入字符串進行單字節編碼,不然,由於charCodeAt()對漢字等符號返回Unicode編碼,其長度爲16bit;所以,可將全部字符當作雙字節處理,雖然增長了字節數量,但簡化了雙字節字符和單字節字符的識別  
  26. 注2:在JavaScript中,CJK ExtB(擴展字符平面2)中的字符均被當作兩個字符,用4Byte編碼,即字符"𠀀"~"𪛖",其編碼0xD840,0xDC00~0xD869~0xDED6,  
  27.     例:語句:alert("𪛖".charCodeAt(0).toString(16)+" "+"𪛖".charCodeAt(1).toString(16));將顯示:d869 ded6  
  28. */  
  29. function unicodeToByte(str) //將Unicode字符串轉換爲UCS-16編碼的字節數組  
  30. {  
  31.     var result=[];  
  32.     for(var i=0;i<str.length;i++)  
  33.         result.push(str.charCodeAt(i)>>8,str.charCodeAt(i)&0xff);  
  34.     return result;  
  35. }  
  36. function byteToUnicode(arr) //將UCS-16編碼的字節數組轉換爲Unicode字符串  
  37. {  
  38.     var result="";  
  39.     for(var i=0;i<arr.length;i+=2)  
  40.         result+=String.fromCharCode((arr[i]<<8)+arr[i+1]);  
  41.     return result;  
  42. }  
  43. var map="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; //Base64從0到63的對應編碼字符集  
  44. function encodeBase64(str)  
  45. {  
  46.     var buffer=0,result="";  
  47.     var arr=unicodeToByte(str);  
  48.     for(var i=0;i<arr.length;i++)  
  49.     {  
  50.         buffer=(buffer<<8)+arr[i];  
  51.         if(i%3==2) //每3個字節處理1次  
  52.         {  
  53.             result+=map.charAt(buffer>>18)+map.charAt(buffer>>12&0x3f)+map.charAt(buffer>>6&0x3f)+map.charAt(buffer&0x3f);  
  54.             buffer=0;  
  55.         }  
  56.     } //3的整數倍的字節已處理完成,剩餘的字節仍存放於buffer中  
  57.     if(arr.length%3==1) //剩餘1個字節  
  58.         result+=map.charAt(buffer>>2)+map.charAt(buffer<<4&0x3f)+"==";  
  59.     else if(arr.length%3==2) //剩餘2個字節  
  60.         result+=map.charAt(buffer>>10)+map.charAt(buffer>>4&0x3f)+map.charAt(buffer<<2&0x3f)+"=";  
  61.     return result;  
  62. }  
  63. function decodeBase64(str)  
  64. {  
  65.     //逆向映射數字索引和Base64編碼字符集(簡單Hash)  
  66.     var s="var base64={";  
  67.     for(var i=0;i<64;i++)  
  68.         s+="\""+map.charAt(i)+"\":"+i+",";  
  69.     s+="\"=\":0};"; //將"="字符對應的編碼定義爲0,免除額外的處理  
  70.     eval(s);  
  71.     var buffer=0,result=[];  
  72.     for(i=0;i<str.length;i++)  
  73.     {  
  74.         buffer=(buffer<<6)+base64[str.charAt(i)];  
  75.         if(i%4==3) //每3個Base64字符處理一次  
  76.         {  
  77.             result.push(buffer>>16,buffer>>8&0xff,buffer&0xff);  
  78.             buffer=0;  
  79.         }  
  80.     } //4的整數倍的Base64字符已處理完成,剩餘的Base64字符仍存放於buffer中  
  81.     if(/==$/g.test(str)) //剩餘2個Base64字符  
  82.         result.push(buffer>>4);  
  83.     else if(/=$/g.test(str)) //剩餘3個Base64字符,不可能剩餘1個Base64字符  
  84.         result.push(buffer>>10,buffer>>2&0xff);  
  85.     return byteToUnicode(result);  
  86. }  
  87. </script> 
  88. <p>Base64編碼、解碼算法<br /><br /> 
  89. 白宇 - 夢遼軟件工做室 - 博訊網絡有限責任公司<br /> 
  90. 2011.05.30</p> 
  91. <table border="0"> 
  92.     <tr> 
  93.         <td>輸入:</td> 
  94.         <td>Base64編碼:</td> 
  95.         <td>Base64解碼:</td> 
  96.     </tr> 
  97.     <tr> 
  98.         <td> 
  99.             <textarea wrap="soft" id="input" cols="40" rows="30"></textarea> 
  100.         </td> 
  101.         <td> 
  102.             <textarea wrap="soft" id="encode" cols="40" rows="30"></textarea> 
  103.         </td> 
  104.         <td> 
  105.             <textarea wrap="soft" id="decode" cols="40" rows="30"></textarea> 
  106.         </td> 
  107.     </tr> 
  108.     <tr> 
  109.         <td align="center"> 
  110.             <input type="button" value="編碼 →" onClick="encode.value=encodeBase64(input.value)" /> 
  111.         </td> 
  112.         <td align="center"> 
  113.             <input type="button" value="解碼 →" onClick="decode.value=decodeBase64(encode.value);" /> 
  114.         </td> 
  115.         <td align="center"> 
  116.             <input type="button" value="校驗 √" onClick="alert(input.value==decode.value?'校驗正確!':'校驗錯誤!');" /> 
  117.         </td> 
  118.     </tr> 
  119. </table> 
  120. </body> 
  121. </html> 

版本二:數組

  
  
  
  
  1. <html xmlns="http://www.w3.org/1999/xhtml"> 
  2. <head> 
  3. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
  4. <title>Base64編碼、解碼算法(版本2) - 夢遼軟件工做室</title> 
  5. <style type="text/css"> 
  6.     body,table {  
  7.         font-family:宋體;  
  8.         font-size:9pt;  
  9.     }  
  10.     input {  
  11.         width:200px;  
  12.         height:25px;  
  13.     }  
  14. </style> 
  15. </head> 
  16. <body> 
  17. <script type="text/javascript"> 
  18. /*  
  19. Base64編碼規則:  
  20. 一、將三個byte的數據,前後放入一個24bit的緩衝區中,先來的byte佔高位;  
  21. 二、數據不足3byte的話,緩衝區中剩下的bit用0補足;  
  22. 三、而後,每次取出6個bit(由於2^6=64,即0到63),按照其值選擇ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/中的字符做爲編碼後的輸出;  
  23. 四、不斷進行,直到所有輸入數據轉換完成;  
  24. 五、若是最後剩下兩個輸入數據,在編碼結果後加1個=;若是最後剩下一個輸入數據,編碼結果後加2個=;若是沒有剩下任何數據,則什麼都不加,這樣能夠保證數據還原的正確性。  
  25. 注1:先對輸入字符串進行單字節編碼,不然,由於charCodeAt()對漢字等符號返回Unicode編碼,其長度爲16bit;所以,可將全部字符當作雙字節處理,雖然增長了字節數量,但簡化了雙字節字符和單字節字符的識別  
  26. 注2:在JavaScript中,CJK ExtB(擴展字符平面2)中的字符均被當作兩個字符,用4Byte編碼,即字符"𠀀"~"𪛖",其編碼0xD840,0xDC00~0xD869~0xDED6,  
  27.     例:語句:alert("𪛖".charCodeAt(0).toString(16)+" "+"𪛖".charCodeAt(1).toString(16));將顯示:d869 ded6  
  28. 技巧:編碼時處理源字節,若是字節總數模3餘1,則可如今其後面添加2個爲0的字節,若是模3餘2,則添加1個爲0的字節,而後在編碼完成後將末尾的2個或1個A字符均替換爲=字符;  
  29.      解碼時一樣能夠將末尾的=字符替換爲A字符,因爲A字符對應0,而0解碼爲空字符,故可不作任何處理(編碼非字符類型的其它字節流,如圖片、音視頻等,則必須將末尾的0字節去除)。  
  30. */  
  31. function unicodeToByte(str) //將Unicode字符串轉換爲UCS-16編碼的字節數組  
  32. {  
  33.     var result=[];  
  34.     for(var i=0;i<str.length;i++)  
  35.         result.push(str.charCodeAt(i)>>8,str.charCodeAt(i)&0xff);  
  36.     return result;  
  37. }  
  38. function byteToUnicode(arr) //將UCS-16編碼的字節數組轉換爲Unicode字符串  
  39. {  
  40.     var result="";  
  41.     for(var i=0;i<arr.length;i+=2)  
  42.         result+=String.fromCharCode((arr[i]<<8)+arr[i+1]);  
  43.     return result;  
  44. }  
  45. var map="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; //Base64從0到63的對應編碼字符集  
  46. function encodeBase64(str)  
  47. {  
  48.     var buffer,result="",flag=0; //flag表示在字節數組剩餘的個數  
  49.     var arr=unicodeToByte(str);  
  50.     flag=arr.length%3;  
  51.     if(flag==1)  
  52.         arr.push(0,0);  
  53.     else if(flag==2)  
  54.         arr.push(0);  
  55.     for(var i=0;i<arr.length;i+=3) //此時arr.length必定能被3整除  
  56.     {  
  57.         buffer=(arr[i]<<16)+(arr[i+1]<<8)+arr[i+2];  
  58.         result+=map.charAt(buffer>>18)+map.charAt(buffer>>12&0x3f)+map.charAt(buffer>>6&0x3f)+map.charAt(buffer&0x3f);  
  59.     }  
  60.     if(flag==1)  
  61.         resultresult=result.replace(/AA$/g,"==");  
  62.     else if(flag==2)  
  63.         resultresult=result.replace(/A$/g,"=");  
  64.     return result;  
  65. }  
  66. function decodeBase64(str)  
  67. {  
  68.     //逆向映射數字索引和Base64編碼字符集(簡單Hash)  
  69.     var s="var base64={";  
  70.     for(var i=0;i<64;i++)  
  71.         s+="\""+map.charAt(i)+"\":"+i+",";  
  72.     s+="\"=\":0};"; //將"="字符對應的編碼定義爲0,至關於將=字符轉換爲A字符  
  73.     eval(s);  
  74.     var buffer,result=[];  
  75.     for(i=0;i<str.length;i+=4) //因爲包含Base64末尾包含1個或2個=字符,故str.length必定能被4整除  
  76.     {  
  77.         buffer=(base64[str.charAt(i)]<<18)+(base64[str.charAt(i+1)]<<12)+(base64[str.charAt(i+2)]<<6)+base64[str.charAt(i+3)];  
  78.         result.push(buffer>>16,buffer>>8&0xff,buffer&0xff);  
  79.     }  
  80.     if(/==$/g.test(str)) //如解碼爲字符串可不作該處理  
  81.     {  
  82.         result.pop();  
  83.         result.pop();  
  84.     }  
  85.     else if(/=$/g.test(str))  
  86.         result.pop();  
  87.     return byteToUnicode(result);  
  88. }  
  89. </script> 
  90. <p>Base64編碼、解碼算法(版本2)<br /><br /> 
  91. 白宇 - 夢遼軟件工做室 - 博訊網絡有限責任公司<br /> 
  92. 2011.05.31</p> 
  93. <table border="0"> 
  94.     <tr> 
  95.         <td>輸入:</td> 
  96.         <td>Base64編碼:</td> 
  97.         <td>Base64解碼:</td> 
  98.     </tr> 
  99.     <tr> 
  100.         <td> 
  101.             <textarea wrap="soft" id="input" cols="40" rows="30"></textarea> 
  102.         </td> 
  103.         <td> 
  104.             <textarea wrap="soft" id="encode" cols="40" rows="30"></textarea> 
  105.         </td> 
  106.         <td> 
  107.             <textarea wrap="soft" id="decode" cols="40" rows="30"></textarea> 
  108.         </td> 
  109.     </tr> 
  110.     <tr> 
  111.         <td align="center"> 
  112.             <input type="button" value="編碼 →" onClick="encode.value=encodeBase64(input.value)" /> 
  113.         </td> 
  114.         <td align="center"> 
  115.             <input type="button" value="解碼 →" onClick="decode.value=decodeBase64(encode.value);" /> 
  116.         </td> 
  117.         <td align="center"> 
  118.             <input type="button" value="校驗 √" onClick="alert(input.value==decode.value?'校驗正確!':'校驗錯誤!');" /> 
  119.         </td> 
  120.     </tr> 
  121. </table> 
  122. </body> 
  123. </html> 

    這是完整的HTML文件(單文件),直接保存後就能夠運行了。網絡

相關文章
相關標籤/搜索