基于JavaScript的Base64编码、解码算法

简介:

 Base64编码是一种很常用的编码,在RSA、AES等加密算法中,密钥对的表示通常使用Base64,UTF-7也是在Base64的基础上变化而来,当然所有仅支持ASCII码传输的网关在传输非ASCII码时,都可以使用Base64编码。

    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个=字符。

    Base64解码的方法与编码相反,将4个Base64编码字符转换为对应的0x0~0x3f,共24Bit,然后重新拆分成3部分,每部分8Bit,即1Byte,若末尾有=字符,则按编码方法中描述的规则反向处理。

    网上有很多现成的算法,但似乎没有使用JavaScript实现的,实际上使用JavaScript实现也不是太复杂。去年我就写了这个程序,只是忘记放在这里了,前天给学生讲课(放假前的最后一课,开学就大四了,可编程的能力尚需锤炼),讲到了这个,特意加了很多注释,放在这里,以飨读者。

    一共写了两个版本,其编码、解码的时间复杂度均为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. 1、将三个byte的数据,先后放入一个24bit的缓冲区中,先来的byte占高位;  
  21. 2、数据不足3byte的话,缓冲区中剩下的bit用0补足;  
  22. 3、然后,每次取出6个bit(因为2^6=64,即0到63),按照其值选择ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/中的字符作为编码后的输出;  
  23. 4、不断进行,直到全部输入数据转换完成;  
  24. 5、如果最后剩下两个输入数据,在编码结果后加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. 1、将三个byte的数据,先后放入一个24bit的缓冲区中,先来的byte占高位;  
  21. 2、数据不足3byte的话,缓冲区中剩下的bit用0补足;  
  22. 3、然后,每次取出6个bit(因为2^6=64,即0到63),按照其值选择ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/中的字符作为编码后的输出;  
  23. 4、不断进行,直到全部输入数据转换完成;  
  24. 5、如果最后剩下两个输入数据,在编码结果后加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文件(单文件),直接保存后就可以运行了。










本文转自 BlackAlpha 51CTO博客,原文链接:http://blog.51cto.com/mengliao/898745,如需转载请自行联系原作者
目录
相关文章
|
4月前
|
存储 JavaScript 前端开发
JS上传文件(base64字符串和二进制文件流)
这篇文章介绍了两种JavaScript文件上传的方法:使用FileReader对象将文件读取为base64字符串上传,以及使用FormData对象以二进制文件流的形式上传文件,包括如何处理文件选择、读取和上传的详细代码示例。
527 2
JS上传文件(base64字符串和二进制文件流)
|
4月前
|
JavaScript 算法 前端开发
JS算法必备之String常用操作方法
这篇文章详细介绍了JavaScript中字符串的基本操作,包括创建字符串、访问特定字符、字符串的拼接、位置查找、大小写转换、模式匹配、以及字符串的迭代和格式化等方法。
JS算法必备之String常用操作方法
|
4月前
|
JavaScript 算法 前端开发
JS算法必备之Array常用操作方法
这篇文章详细介绍了JavaScript中数组的创建、检测、转换、排序、操作方法以及迭代方法等,提供了数组操作的全面指南。
JS算法必备之Array常用操作方法
|
4月前
|
JavaScript 算法 前端开发
"揭秘Vue.js的高效渲染秘诀:深度解析Diff算法如何让前端开发快人一步"
【8月更文挑战第20天】Vue.js是一款备受欢迎的前端框架,以其声明式的响应式数据绑定和组件化开发著称。在Vue中,Diff算法是核心之一,它高效计算虚拟DOM更新时所需的最小实际DOM变更,确保界面快速准确更新。算法通过比较新旧虚拟DOM树的同层级节点,递归检查子节点,并利用`key`属性优化列表更新。虽然存在局限性,如难以处理跨层级节点移动,但Diff算法仍是Vue高效更新机制的关键,帮助开发者构建高性能Web应用。
80 1
|
4月前
|
算法 5G vr&ar
基于1bitDAC的MU-MIMO的非线性预编码算法matlab性能仿真
在现代无线通信中,1-bit DAC的非线性预编码技术应用于MU-MIMO系统,旨在降低成本与能耗。本文采用MATLAB 2022a版本,深入探讨此技术,并通过算法运行效果图展示性能。核心代码支持中文注释与操作指导。理论部分包括信号量化、符号最大化准则,并对比ZF、WF、MRT及ADMM等算法,揭示了在1-bit量化条件下如何优化预编码以提升系统性能。
|
4月前
|
算法
【Azure Developer】完成算法第4版书中,第一节基础编码中的数组函数 histogrm()
【Azure Developer】完成算法第4版书中,第一节基础编码中的数组函数 histogrm()
|
5月前
|
机器学习/深度学习 存储 算法
编码之舞:从算法到应用的探索之旅
在数字化时代的浪潮中,编程技术如同一种语言,连接着人类与机器。本文将带领读者踏上一场自数据结构基础至高级算法应用的探索旅程,通过实际案例分析,揭示算法在现代软件开发中的重要作用,并分享作者在编程实践中的心得体会,旨在为初学者和资深开发者提供有价值的参考与启示。
|
4月前
|
JavaScript 前端开发
JS - 如何上传 Base64 编码的图片
本文展示了如何将Base64编码的图片在前端转换为Blob对象,并使用`FormData`上传到服务器端的方法。
200 0
|
5月前
|
机器学习/深度学习 算法 计算机视觉
通过MATLAB分别对比二进制编码遗传优化算法和实数编码遗传优化算法
摘要: 使用MATLAB2022a对比了二进制编码与实数编码的遗传优化算法,关注最优适应度、平均适应度及运算效率。二进制编码适用于离散问题,解表示为二进制串;实数编码适用于连续问题,直接搜索连续空间。两种编码在初始化、适应度评估、选择、交叉和变异步骤类似,但实数编码可能需更复杂策略避免局部最优。选择编码方式取决于问题特性。
下一篇
DataWorks