字符编码
ASCII码于1961年提出,用于在不同计算机硬件和软件系统中实现数据传输标准化。其中95个字符可以显示。另外33个不可以显示。标准ASCII码是7位编码,但由于计算机基本处理单位为字节(1byte=8bit),所以一般仍以一个字节来存放一个ASCII字符。每一个字节中多余出来的一位(最高位)在计算机内部通常保持为0(在数据传输时可用作奇偶校验位)。
0~31及127(共33个)是控制字符或通信专用字符(其余为可显示字符),如控制符:LF(换行)、CR(回车)、FF(换页)、DEL(删除)、BS(退格)、BEL(振铃)等;通信专用字符:SOH(文头)、EOT(文尾)、ACK(确认)等;ASCII值为8、9、10和13分别转换为退格、制表、换行和回车字符。它们并没有特定的图形显示,但会依不同的应用程序而对文本显示有不同的影响。
32~126(共95个)是字符(32sp是空格),其中48~57为0到9十个阿拉伯数字,65~90为26个大写英文字母,97~122为26个小写字母,其余为一些标点符号、运算符号等。
要处理中文显然一个字节是不够的,至少需要两个字节,而且还不能和ASCII编码冲突,所以,1980年中国制定了GB2312编码,用来把中文编进去。GB2312是一个简体中文字符集,用两个字节(8位2进制)表示一个汉字,理论上最多可以表示256×256=65536个汉字,由6763个常用汉字和682个全角的非汉字字符组成。其中汉字根据使用的频率分为两级。一级汉字3755个,二级汉字3008个。
GBK即汉字内码扩展规范,K为扩展的汉语拼音中“扩”字的声母。标准兼容GB2312,共收录汉字21003个、符号883个,并提供1894个造字码位,简、繁体字融于一库。GBK采用双字节表示,总计23940个码位,共收入21886个汉字和图形符号,其中汉字(包括部首和构件)21003 个,图形符号883 个。
在台湾、香港与澳门地区,使用的是繁体中文字符集,而GB2312面向简体中文字符集,并不支持繁体汉字。在这些使用繁体中文字符集的地区,一度出现过很多不同厂商提出的字符集编码,这些编码彼此互不兼容,造成了信息交流的困难。为统一繁体字符集编码,1984年,台湾五大厂商宏碁、神通、佳佳、零壹以及大众一同制定了一种繁体中文编码方案,因其来源被称为五大码,英文写作Big5,后来按英文翻译回汉字后,普遍被称为大五码。大五码是一种繁体中文汉字字符集,其中繁体汉字13053个,808个标点符号、希腊字母及特殊符号。
不同的国家和地区制定了不同的标准,这些使用2个字节来代表一个字符的各种延伸编码方式,称为ANSI编码。在简体中文系统下,ANSI编码代表GB2312编码,在日文操作系统下,ANSI编码代表JIS编码,所以在中文windows下要转码成gb2312,gbk只需要把文本保存为ANSI编码即可。不同ANSI编码之间互不兼容,这样就容易造成混乱。导致了unicode码的诞生。Unicode把所有语言都统一到一套编码里,这样就不会再有乱码问题了。
Unicode是一个很大的集合,现在的规模可以容纳100多万个符号。每个符号的编码都不一样,Unicode固然统一了编码方式,但是它的效率不高,比如UCS-4(Unicode的标准之一)规定用4个字节存储一个符号,那么每个英文字母前都必然有三个字节是0,这对存储和传输来说都很耗资源。为了提高Unicode的编码效率,于是就出现了UTF-8编码。UTF-8可以根据不同的符号自动选择编码的长短。比如英文字母可以只用1个字节就够了。
在计算机内存中,统一使用Unicode编码,当需要保存到硬盘或者需要传输的时候,就转换为UTF-8编码。用记事本编辑的时候,从文件读取的UTF-8字符被转换为Unicode字符到内存里,编辑完成后,保存的时候再把Unicode转换为UTF-8保存到文件,浏览网页的时候,服务器会把动态生成的Unicode内容转换为UTF-8再传输到浏览器
各个国家的电脑都需要通信,而通信的一种方式就是使用URL地址。每个国家都希望把这个地址写成自己国家的语言。但这会导致其他国家根本没法访问地址,因为打不出这个字符。所以,人类迫切需要一种中间编码形式,既能够兼容ASCII码,又能够把任意一种编码形式转换成只使用可读字符就能表示的编码。其中一种编码形式,就是Base64编码。Base64编码,顾名思义,用64个可读字符进行编码。与Hex的16个字符相比多了很多,但是比ASCII码又少了一倍,去除了不可读字符。标准Base64编码包含10个数字,26个小写字母,26个大写字母和加号+以及斜杠/共计64个。
在utf-8编码中,一个汉字为3个字节,一个字母一个字节,每个字节又包含8位的二进制码,由于base64编码最大支持64个字符,用二进制表示最大为111110(十进制为63),即6位二进制码即可,那么base64编码就是把所有字节的二进制码连接到一起,然后从头开始每6位分割一个,二进制序列有时不能正好平均地分为6位的块,在这种情况下,就在序列末尾填充x(不一定是x,这里x仅仅是个泛指,这个填充最后不输出,仅仅是为了区别是否包括原始数组中的位,其实二进制中填充只能填充0或者1),使二进制序列的长度成为24的倍数(6和8的最小公倍数)。
对已填充的二进制进行编码时,任何完全填充(不包括原始数组中的位)的6位组都有特殊的第65个符号"="表示。如果6位组是部分填充的,就将填充位设置为0.
具体步骤如下:
1、把字符串按照字节分割为数组;
2、把数组中的每个元素都转换为ASCII码值,然后把这些值分别转换为二进制;
3、把计算的二进制连接为一个整体的字符串;
4、计算字符串的位数,如果不是24的倍数那么在最后位补x知道位数位24的倍数;
6、把字符串按照每6位一个分割;
7、把每个6位的二进制数值转换位十进制;
8、每个转换的十进制码分别对应base64表转换位base64码;最后如果不全是x则把x转换为0,然后转换为十进制,如果全部为x则转换为等号=
9、把转换的base64码连接位一个字符串
用php代码表示为:
header("Content-Type:text/html; charset=utf-8");//指定编码
$str='你aF好';//要转换的字符串
$arr=str_split($str);//把字符串按照字节分割为数组
$s='';
$t='';
foreach($arr as $v){
$s.=strlen(decbin(ord($v)))<8?str_pad(decbin(ord($v)),8,0,STR_PAD_LEFT):decbin(ord($v));//ord函数把数组元素转换为ASCII码,然后使用decbin函数转换为二进制,如果转换以后的二进制位数不足8位则总左侧填充0直到8位,最后把这些二进制连接为一个字符串
}
$t=$s.'xxxxxxxx';//字符串的位数为64,不是24的倍数,向上数最小的24的倍数为72,在字符串后面填充8个x
$r=str_split($ss,6);//把填充后的字符串按照6位一个分割为数组
然后循环数组$r,如果元素中全部为数组则直接转化为对应的十进制并对应bsae64码输出,如果元素中包含数字和x则把x转化为0然后在转化为十进制并对应base64码输出,如果全部是x则直接输出等号=。最后把所有输出连接程一个字符串即为对应的base64编码。
汉字的三个二进制码中最高位都是1,字母的二进制码中最高位为0,这个在解码base64码的时候可以用来判断是否是汉字或字母。
误区:Base64不是加密算法很多博客什么的都把Base64当做加密算法,这是不对的。Base64不具有可读性,但不代表这个编码是加密的。加密需要保证,没有密钥的人无法解密信息,无法从密文中获得任何明文信息。Base64编码显然没有密钥什么事… 所以,这个误区大家要纠正过来。
base64编码表:
