位(bit)、字节(byte)、字符、编码之间的关系
1、位:
数据存储的最⼩单位。每个⼆进制数字0或者1就是1个位;
2、字节:
8个位构成⼀个字节;即:1 byte (字节)= 8 bit(位);
1 KB = 1024 B(字节);
1 MB = 1024 KB;  (2^10 B)
1 GB = 1024 MB;  (2^20 B)
1 TB = 1024 GB;  (2^30 B)
3、字符:
a、A、中、+、*、の......均表⽰⼀个字符;
⼀般 utf-8 编码下,⼀个汉字 字符 占⽤ 3 个 字节;
⼀般 gbk 编码下,⼀个汉字  字符  占⽤ 2 个 字节;
4、字符集:
即各种各个字符的集合,也就是说哪些汉字,字母(A、b、c)和符号(空格、引号..)会被收⼊标准中;
5、编码:
规定每个“字符”分别⽤⼀个字节还是多个字节存储,⽤哪些字节来存储,这个规定就叫做“编码”。(其实际是对字符集中字符进⾏编码,即:每个字符⽤⼆进制在计算中表⽰存储);
通俗的说:编码就是按照规则对字符进⾏翻译成对应的⼆进制数,在计算器中运⾏存储,⽤户看的时候(⽐如浏览器),在⽤对应的编码解析出来⽤户能看懂的;
(1)标准ASCii字符集:有96个打印字符,和32个控制字符组成;⼀共96+32=128个;
⽤7位⼆进制数来对每1个字符进⾏编码;
⽽由于7位还还不够1个字节,⽽电脑的内部常⽤字节来⽤处理,每个字节中多出来的最⾼位⽤0替代;
0 000  0000 0
0 111    127;  从0----127,来表⽰128个ACSii编码;
⽐如:字符 'A'----------在计算器内部⽤0100 0001 (65)来表⽰;
字符'a'-----------在计算器内部⽤0 110 0001 (97)来表⽰;
注意:'10'在计算器内部是没有编码的,因为它是字符串,⽽不是单个字符。可以分别对1,0字符编码存储;
(2)扩展ASCii字符集:将标准的ASCii最⾼位1,得到⼗进制代码128---255(1 000 0000----1 111 1111);所以字符集⼀共有0---255,  256个字符;
(3)gb2312字符集: 所有汉字字符在计算机内部采⽤2个字节来表⽰,每个字节的最⾼位规定为1【正好与标准ASCii 字符(最⾼位是0)不重叠,并兼容】,不⽀持繁体字;
所以:gb2312表⽰汉字的编码为:[129--255][129--255]  (两个字节,每个字节最⾼位是1);⼩于127的字符,与ASCii编码相同;
(4)gbk字符集:gb2312的扩充,兼容gb2312,除了收录gb2312所有的字符外,还收录了其他不常见的汉字、繁体字等;
gbk中字符是⼀个或两个字节,单字节字符00--7F(0---127)这个区间和ASCII是⼀样的;
双字节字符的第⼀个字节是在81--FE(129--254)之间。通过这个可以判断是单字节还是双字节;
即:在gbk字符编码,如果第⼀个字节是>128的,则再往后⼀个字节,组成汉字;如果第⼀个字节<128,则表⽰的是⼀个单字节(此时和ASCII是⼀样的);
// gbk编码下,⽆乱码截取中⽂字符;
// ⽅法1:⾃定义函数1;
function subgbk($str,$lens){  // 形参 $str 表⽰将要截取的原始字符串, $lens 表⽰设定需要截取的字符个数; if($lens<=0){
return '';
}
$chars = 0;  // 计算,统计已经截取的字符个数;
$res = '';    //  已经截取的字符长度;
$offset = 0;  // 偏移量,从字符串中那个字节开始截取;
$lengths = strlen($str);    // 将要截取的原始字符串字节的数;
while($chars<$lens && $offset<$lengths){
$hight = ord(substr($str,$offset,1));  // 计算出 gbk字符中⾼字节的所对应编码的值;
if($hight>128){
// 截取两个字节,代表⼀个字符;即:双字节字符;
$count = 2;
}else{
//截取⼀个字节,代表⼀个字符,即:单字节字符;
$count = 1;
}
$res .= substr($str,$offset,$count);
$offset += $count;
$chars++;
}
return $res;
}
>
// ⽅法2:⾃定义函数2;
// 思路:先把字符串中所有的字符逐⼀取出来组成数组,然后对数组元素进⾏截取;最后截取出的数组拼接成想要的字符串;
function strgbk2($str,$strat,$length=NULL){  // 第三个参数默认设置的值是NULL,这个参数是参考了下边的array_slice()函数,如果省略的话,则表⽰,⼀直截取到最 $zijielen = strlen($str);    //  计算出原始字符串 $str 的字节长度;
$chars = 0;    // 统计计算截取的字符数;
$zifuarr = array();  //将字符串按照字符的形式分割到数组中;(待存储);
for($i = 0;$i<$zijielen;){  // $i 表⽰原始字符串 $str 中的字节(标记);
if(ord(substr($str,$i,1)) > 128){
// 双字节字符,两个字节来表⽰⼀个字符;
$zifuarr[] = $str[$i].$str[$i+1];
// $zifuarr[] = substr($str,$i,2);    两种写法的意思是⼀样的,都是取得某个字符某些的字节;
$i += 2;
}else{
//  单字节字符,⼀个字节表⽰⼀个字符;
$zifuarr[] = $str[$i];
// $zifuarr[] = substr($str,$i,1); 两种写法的意思是⼀样的,都是取得某个字符某个的字节;
$i++;
}
$chars++;        // 每次循环,相当于截取⼀个存储字符;  相当于所有的数组元素个数 count($zifuarr);
}
if($chars < $strat){    //  当偏移过字符总长度时候;(开始截取的位置,已经超过了字符的总长度);
return 'No characters have been found !';
}
return implode(array_slice($zifuarr,$strat,$length));  // array_slice()是截取数组⼀部分;implode()是将截取出来的字符串,链接起来;
}
>
<?php
// ⽅法3:⽤php内置的函数 mb_substr截取;
//此函数和 mb_strlen()函数⼀样,都是针对多字节字符的操作函数,在特定的编码下,针对字符的截取(mb_substr)和长度的计算(mb_strlen);
$strgbk = 'ds我是fdg⼀个中国xghdt⼈';
echo mb_substr($strgbk,2,3,'gbk');  // 我是f
>
(5)Unicode字符集:容纳世界上所有语⾔字符和符号的集合;(以及对应的⼆进制数字);
Unicode只是⼀个编码规范,⽬前实际实现的unicode编码只要有三种:UTF-8,UCS-2和UTF-16,三种unicode字符集之间可以按照规范进⾏转换。
(6)utf-8编码:UTF-8(8-bit Unicode Transformation Format)是⼀种针对Unicode的可变长度字符编码,也是⼀种前缀码。它可以⽤来表⽰Unicode标准中的任何字符,且其编码中的第⼀个字节仍与ASCII兼容,这使得原来处理ASCII字符的软件⽆须或只须做少部分修改,即可继续使⽤。因此,它逐渐成为电⼦邮件、⽹页及其他存储或发送⽂字的应⽤中,优先采⽤的编码。
ascii是几位二进制编码
对于UTF-8编码中的任意字节B,如果B的第⼀位为0,则B独⽴的表⽰⼀个字符(ASCII码);
如果B的第⼀位为1,第⼆位为0,则B为⼀个多字节字符中的⼀个字节(⾮ASCII字符);
如果B的前两位为1,第三位为0,则B为两个字节表⽰的字符中的第⼀个字节;
如果B的前三位为1,第四位为0,则B为三个字节表⽰的字符中的第⼀个字节;
如果B的前四位为1,第五位为0,则B为四个字节表⽰的字符中的第⼀个字节;
因此,对UTF-8编码中的任意字节,根据第⼀位,可判断是否为ASCII字符;根据前⼆位,可判断该字节是否为⼀个字符编码的第⼀个字节;根据前四位(如果前两位均为1),可确定该字节为字符编码的第⼀个字节,并且可判断对应的字符由⼏个字节表⽰;根据前五位(如果前四位为1),可判断编码是否有错误或数据传输过程中是否有错误。
即:
1、单字节的字符,字节的第⼀位设为0,对于英语⽂本,UTF-8码只占⽤⼀个字节,和ASCII码完全相同;
2、n个字节的字符(n>1),第⼀字节的前n位设为1,第n+1位设为0,后⾯字节的前两位都设为10;
3、2个字节,第⼀个字节的前2位是1;3个字节,第⼀个字节的前三位是1; 4个字节,第⼀个字节的前4位都是1;
// 如何截取中⽂,⽆乱码,假设utf-8编码;