PHP字符编码ASCII 、GB2312、GBK、UTF-8解释

变量命名规则:
1.  变量名区分大小写(case-sensitive) 。
2.  必须字母或下划线开头。变量名可由 字母、数字、下划线组成。  



到这里可能,很多人纳闷了~。那为啥  $我是变量    这样的中文也能做变量名呢?
在PHP里,中文的确是可以做变量名的(能用是能用但千万别项目上用....) 。 因为这里的字母是指: a-z   A-Z  和  扩展ASCII
字符里从 127 到 255  ,16进制表示为:0x7f-0xff   。 那意思就是ASCII字符里从127到255
(0x7f-0xff) 涵括了中文? 的确是这样的。下面就简单的讲下编码。

ASCII 、GB2312、GBK、UTF-8  编码:


ASCII :
ASCII 编码里包括了128个字符。用 十进制 0  到 127 来表示 。那就对了, 0 到 127 不就是 128个字符吗。 每一个数字都代表一个字符。看ASCII 编码表


们先看十进制(Dec) 这列,看到了吗 。 十进制数字  9 对应 的字符是 我们开发用得最多的 TAB键。 再看看 48 对应的字符是  0
。没错从  ASCII  48开始 到57 都表示数字  0到9 。  ASCII  97 到 122 表示 小写字母 a 到 z 。  
比如: 我们看到的字母 a  ,其实计算机并不认识啥 字母a , 她只认识  97。 她把a 转成了 ASCII 97来进行存储。下面用PHP
来玩玩 ASCII 。

来我们认识两个函数:
ord  ----  Return ASCII value of character     返回 字符的 ASCII 值 。
chr  ----  Return a specific character     返回 ASCII 对应的 字符。

翠花上例子:
<?php echo(ord(‘a‘));?>

//输出   97  
没错吧,  小写a的 ASCII 就是  97。   要把 ASCII 97  对应的字符打印出来:
<?php echo(chr(97));?>

//输出 a
恩。看完基本就明白了。  ASCII 编码 里面包括了  大小写字母   数字 和 一些常用的控制字符。 这样在使用英语的国家基本就能使用了。计算机存储的是ASCII 。 人看到的就是 ASCII 对应的字符。

GB2312 编码:
世界上并不全是用英语作为语言的。比如我国用的是中文。小日本用的是 日语。 韩国用的是韩文。 这些语言和英语完全不是一回事。 你看ASCII 表上有中文对应的”数字“吗?没有吧。因为还有一份 GB2312编码表 ,和ASCII 编码表道理一样。  链接: http://wenku.baidu.com/view/244e2d2ce2bd960590c677a6.html     大家打开一看,哎呀~~! 是否有点乱乱,找不到头绪,啥乱七八糟。 不过当明白原理,就容易看懂了。


GB2312编码里面,一个字符我们需要用两个字节来进行存储和表示。我们记得ASCII 编码里面
一个字符只需要一个字节。所以以GB2312存储数据比 ASCII 大一倍。 那么GB2312 这两个字节,分别放啥数字 才能表示字母 a 呢?
我们知道 ASCII 编码  a  就一个字节表示,编码97。 GB2312 编码比 ASCII 复杂一点,

在要看懂 GB2312编码表之前,首先我们要学习下”区位码“。

区位码概念:
GB2312对汉字和其他字符(字母,数字等)进行了“分区”。
       01-09区为特殊符号(数字呀、字母呀等)。
       16-55区为一级汉字,按拼音排序。
       56-87区为二级汉字,按部首/笔画排序。

分区是啥?比如我是广西的,你是河南的、他是广东。 也就是说每个字符肯定存在于某个区里。  这种表示方式叫做 “区位码”。  区位码 其实是   区号和位号(表示一个字符在这个哪个区里的第几列) 。 你想知道每个汉字的区位码?简单呀。给你个链接自己查去  http://www.jscj.com/index/gb2312.php


们以   “啊” 这个汉字来查它的区位码。  以上图所示   1601  是 “啊”这个汉字的区位码。  区号是 16
,  位号  01。     如果大家还记得,  16区 是 一级汉字哦。牛X呀。一级汉字是啥意思?
我估计是常用的汉字?~我也不知道,这个是国内专家定义的。  位号 是 01   ,位号其实就是说你在这个区里排行老几。  有了
x轴(区号)和y轴(位号) 那么自然就又个交点,通过交点就能在 GB2312编码表上找到对应的汉字了。

如果你现在就去看 GB2312的编码表,我估计你还是看不懂,虽然说通过区位码就能定位到GB2312编码的字符了。但是GB2312编码表上并没那么单纯。 还要继续往下看。

上面我们说的是GB2312的  区位码: 区号和位号。   前面我说过,一个GB2312的字符 是用两个字节来表示的:(高位字节,低位字节)。第一个字节称为“高位字节” ,第二个字节称为“低位字节”  ps:因为高的一般排左边吧~  所以叫 高位字节....    。
算法如下: 一个GB2312的字符  ==  (0xA0 + 区号,0xA0 + 位号)。按照这个算法,你再取看 GB2312编码表,你就看得如鱼得水了。

0xA0
是啥意思呢?  为啥高位字节 等于 区号 加上  0xA0 。  为啥低位字节 等于 位号 加上
0xA0呢。这样组合起来的两个字节就能表示一个 GB2312的字符?  没错,就是那么简单。 0xA0 是一个16进制数字  换算成
十进制其实就等于 160 。   高位字节 等于  160 加上 区号,你可以理解为,其实就是 GB2312编码字符 是从 160 起步的。
就好比 ASCII 编码是从 0开始  到  127 结束。

我们重新来看下算法  : 一个GB2312的字符  ==  (0xA0 + 区号,0xA0 + 位号) 。

上所看,只要我们知道 区位码(区号和位号)就能算出一个汉字的GB2312编码数字。 字母a 的区位码 : 0365 ,也就是区号 03   位号
65 。  按照上面算法我们算下。 把 0xA0 换成十进制  等于 160。 也就是 (160+03,160+65)    等于  
(163,225) 换成 16进制(编码表一般都是16进制)  (A3,E1) 。   OK了。   字母a 的gb2312编码
出来了,拿着   A3E1去  GB2312编码表去找这个16进制数字对应的字符吧。 如果你没看错的话,没错就是对应着 编码表上的字母 a
。  
所以, 只要记得 上面公式, 找个工具算出汉字区位码,然后套进公式里面算下。就能的到这个字符的GB2312编码值了。  大家可以自己动手去试试算出上面的汉字 “啊”  的GB2312的编码值。

小总结一下,大家记住:
ASCII 编码的范围  --   十进制 => 0 - 127 。  十六进制: 0x00  -  0x7F 。
GB2312编码的范围  --   十进制 => 高位字节:161 - 247 。十六进制:0xA1 - 0xF7  , 低位字节:  161 - 254 。十六进制:0xA1 - 0xFE  。

GBK 编码:
GB2312 之上的一种扩展编码,GBK 编码已经包括了GB2312编码,并扩展了GB2312编码,使它能表示更多的字符。  GB2312和GBK 原理一样,他们区别只是,编码值范围不一样了。 GBK 更大了。
GB2312 编码值范围 :   高字节从A1到F7,而低位字节从A1到FE。
GBK 编码值范围:  高字节从81到FE,而低位字节从40到FE 。

以上范围可以看出。GBK 比  GB2312大很多。   大是大了很多... 不过现在一般项目都用UTF-8编码了。 接下来将下UTF-8编码方式

UTF-8编码:

界上那么多国家,每个国家的语言都不一样。一会出个 ASCII 一会出个 GBK 一会出个 XXOO
编码。那崩溃了。是否能发明一种编码方式,能很好的表示出所有语言呢?
Unicode编码就是这样产生的。这里我们只讲Unicode中得一种实现方式。UTF-8,当然还有其他的实现方式。但对于我们WEB开发来说,并不
常用。

ASCII 编码能很好的表示字母、数字等。所以UTF-8 就在它的基础上进行了一下扩展。  按照惯例,我们还是先看下 Unicode编码 表(UTF8编码表?木有。我们需要掌握如何从Unicode 转换成 utf8)

学习这节的目的

  • 掌握从Unicode 转换成utf8编码的方法
  • 判断UTF-8下的字符的字节数。  看下表:
  •  

unicode 字节位表

unicode 编码范围 十进制/十六进制 UTF-8 字节模板二进制/十六进制 字节数
(0)000000 – (127)00007F 0xxxxxxx(00-7F) 一字节
(128)000080 – (2047)0007FF 110xxxxx(C2-DF)      10xxxxxx 两个字节
(2048)000800 – (55295)00D7FF (57344)00E000 – (65535)00FFFF 1110xxxx(E0-EF)     10xxxxxx     10xxxxxx 三个字节
(65536)010000 – (1114111)10FFFF 11110xxx(F0-F4) 10xxxxxx 10xxxxxx 10xxxxxx 四个字节

这个表很重要,记下这个表就基本了解了UTF-8 是怎么一回事。  UTF-8 一共能用四个字节来表示。 但一般字符呢基本用三个字节就能满足了。

一个字节等于8位。这个大家都知道。   从 00000000   -   11111111    这个就是一个字节的数值范围。   换算成十进制就是  0  -  255 。  懂了这个我们继续往下讲。

继续看上图,   我们慢慢讲:

UTF-8中之 一字节:

在UTF-8里面对ASCII 编码进行了保留然后再它之上进行了扩展补充。 一个字节 存的 还是字母呀  数字呀 和ASCII 编码一样。所以 编码范围也是   0  -  127 。

点同学纳闷为啥是  127 呢? 一个字节换算成二进制不是 255吗?  因为一字节的时候,第一位给借去了,第一位的值为 固定为0  
。大家看上图第一行 “UTF-8字节模板“ 这一列 就明白了。所以其实只有7位是用来表示字符。那么 换算了下 7位  的二进制 就只有  
0  -  127  了。 这个几乎和ASCII 编码一样,  想知道0  -  127 都分别对应了什么字符? 看ASCII 编码表呀。

UTF-8 之两字节:

个字节 8位,两个字节就16位了。哇!值更大了,能表示的字符更多了。所以什么希腊字母呀、拉丁字母呀等都可以用两字节来表示了。 看 第二行的
”UTF-8字节模板“ 这一列 。110xxxxx      10xxxxxx          一共有16位, 每8位一个字节。
大家知道,在一个字节的时候,第一位是不能用的。  两个字节的时候稍微不同了。 在两个字节的时候,
第一个字节的前三位给借去了,同时第二个字节的前两位也是给借去了。    恩在这里,我们只要明白一个地方就行。   UTF-8 编码中
当字符是两个字节表示的时候,第一个字节的编码值范围是多少?    第一个字节是 : 110xxxxx   。   那么也就是范围从  
11000000  -  11011111     换成十六进制范围是   C2  -   DF  。   恩懂这一点,就足够了。  以后遇到 写
UTF-8编码 下的 截取 函数 、统计长度函数 就不用怕了。

UTF-8 之三字节:

个字节表示,是我们用的最多的,因为俺们写中文的嘛。  不过这里注意下就是 ,三字节下的借位情况。  继续看上图 。  
1110xxxx(E0-EF)     10xxxxxx     10xxxxxx     看到了吗?你懂的~
如果还不懂...还是继续重头看起吧。  UTF-8 下 一个字符三字节的。  第一个字节 的范围是多少? 这个必须弄清楚。 范围是从  
11100000  -  11101111   十六进制是: E0   -  EF  。

UTF-8 之四字节:
这个遇到真不多。 不过道理  你真懂了。我就不说了

好了。我们完成了一个目标了 : 判断UTF-8下的字符的字节数。比如以后开发你遇到:

于这段文字 :  "逆雪寒之PHP拾遗"        。 我要在UTF-8下统计它的字符长度  和  实现截取字符窜。  
应该没那么心慌了。  当然有人说,统计字符长度和截取中文字符窜不是很简单吗?mb_strlen 、 mb_substr 。 的确是可以呀。
但我想我们要知其然知其所以然 。 我们的目标是 PHP产品级研发。 不是 PHP企业网站级研发  -_-! 。

接下来完成另外一个目标: 掌握从Unicode 转换成utf8编码的方法


们继续看 unicode 字节位表  。 看第一列    unicode 编码范围 。 四个字节,所以就有四个范围 。
看这个  (0)000000 – (127)00007F       十进制从 0 开始到  127  。这个就是第一字节的unicode
范围。  其他的也是同一个意思。
明白了上面讲的以后,现在开始讲 unicode 编码转换 UTF-8的流程:

我们用 “啊” 这个汉字为例,它的 Unicode 编码是  U+554A (怎么知道的?查 unicode 编码表呀 大哥...) 。 然后我们转成UTF-8 :

  • U+554A
    换成十进制是  21834  。 比对  上面的  unicode 字节位表 的第一列  。看到  21834
    是在  三个字节的  (2048)000800 – (55295)00D7FF  范围之内。  因为  “啊”  在UTF-8 里是三个字节的。
  • 三个字节 的UTF-8模板  是(看 unicode 字节位表 )   1110xxxx      10xxxxxx     10xxxxxx      。
  • "啊“  的   U+554A换算成二进制是 : 1010  101010 01010
  • 把15位二进制按照顺序的填入(不足最后补0)  三字节的 UTF-8 模板里面  。也就是    11101010  10101010  10010100   。    第三字节 不足位,所以最后补0.
  • 最后结果 ,0xEA  0xAA  0x94  这三个就是 ”啊“  字的UTF-8编码了。

附送: Unicode  编码表  http://wenku.baidu.com/view/01a4feeae009581b6bd9ebe1.html


于讲完了编码。。。 那么回过头来。。讲了那么多废话就是为了解释。 为啥 PHP能用中文来做变量名。 PHP官方文档给的
变量名正则表达式‘[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*‘ 。 里面的\x7f \xff
我想大家都明白了吧。。。 \x7f - \xff 的十进制是: 127 - 255。 那么按照我们之前上面讲的那些 编码规则~ 每个字节的编码
都是在 127 - 255范围之内对吧?除了一字节。 那么也就是说 中文无论是GBK GB2312 还是UTF-8编码的,
用来做变量名都是符合了‘[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*‘ 这条正则的。
接下来我们也不要浪费了前面所学了哪些编码知识。。我们要应用,我们要深入了解...所以开始写两个函数,估计大家都在开源的代码。比如啥 phpcms
啥 uchome discuz 里面 看到过类似这些函数。没错~~! 理解完上面的编码知识。我相信 这些对你来说~~ 小菜一碟...

复制代码

  1. //截取字符串字串-GBK (PHP)
  2. function  gb_substr( $str ,  $len ){
  3. $count  = 0;
  4. for ( $i =0;  $i < strlen ( $str );  $i ++){
  5. if ( $count  ==  $len )  break ;
  6. if (preg_match( "/[\x80-\xff]/" ,  substr ( $str ,  $i , 1))) ++ $i ;
  7. ++ $count ;
  8. }
  9. return   substr ( $str , 0,  $i );
  10. }

复制代码

    1. //统计字符串长度-UTF8 (PHP)
    2. function  utf8_strlen( $str ) {
    3. $count  = 0;
    4. for ( $i  = 0;  $i  <  strlen ( $str );  $i ++){
    5. $value  = ord( $str [ $i ]);
    6. if ( $value  > 127) {
    7. if ( $value  >= 194 &&  $value  <= 223)  $i ++;
    8. elseif ( $value  >= 224 &&  $value  <= 239)  $i  =  $i  + 2;
    9. elseif ( $value  >= 240 &&  $value  <= 247)  $i  =  $i  + 3;
    10. else   die ( ‘Not a UTF-8 compatible string‘ );
    11. }
    12. $count ++;
    13. }
    14. return   $count ;
    15. }
时间: 2024-11-08 12:23:51

PHP字符编码ASCII 、GB2312、GBK、UTF-8解释的相关文章

Android中检测字符编码(GB2312,ASCII,UTF8,UNICODE,TOTAL——ENCODINGS)方法(一)

package com.android.filebrowser; import java.io.*; import java.net.*; public class FileEncodingDetect { static final int GB2312 = 0; static final int ASCII = 1; static final int UTF8 = 2; static final int UNICODE = 3; //static final int GBK = 4; //st

彻底搞清楚字符编码: ASCII, ISO_8859, GB2312,UCS, Unicode, Utf-8

彻底搞清楚字符编码: ASCII, ISO_8859, GB2312,UCS, Unicode, U 1.ASCII: 0-127(128-255未使用),美国标准 2.IS0-8859-1(latin-1): 0-255, 西欧国家等 3.GB2312:常用简体中文,双字节编码,国标,对于ASCII字符仍采用单字节编码 4.GBK: GB2312的超集,包含繁体,日韩,双字节编码,不是国标(新的国标GB18030-2000是GBK的超集) 5.BIG5:繁体中文,台湾,类似GB2312 6.S

Android中检测字符编码(GB2312,ASCII,UTF8,UNICODE,TOTAL——ENCODINGS)方法(二)

Intent intent = getIntent(); String contentUri = null; Uri uri =null; if (intent.getData() != null) { uri = intent.getData(); contentUri = "file".equals(uri.getScheme()) ? FileContentProvider.BASE_URI + uri.getEncodedPath() : uri.toString(); Str

字符编码ASCII,Unicode和UTF-8

http://blog.csdn.net/pipisorry/article/details/42387045 ASCII码 ASCII码一共规定了128个字符的编码,比如空格"SPACE"是32(二进制00100000),大写的字母A是65(二进制01000001).这128个符号(包括32个不能打印出来的控制符号),只占用了一个字节的后面7位,最前面的1位统一规定为0. 非ASCII编码 英语用128个符号编码就够了,但是用来表示其他语言,128个符号是不够的.比如,在法语中,字母

java中的常用字符编码ASCII、Unicode和UTF-8

首先讲一下几种字符的编码方式: 1. ASCII码 我们知道,在计算机内部,所有的信息最终都表示为一个二进制的字符串.每一个二进制位(bit)有0和1两种状态,因此八个二进制位就可以组合出256种状态,这被称为一个字节(byte).也就是说,一个字节一共可以用来表示256种不同的状态,每一个状态对应一个符号,就是256个符号,从0000000到11111111. 上个世纪60年代,美国制定了一套字符编码,对英语字符与二进制位之间的关系,做了统一规定.这被称为ASCII码,一直沿用至今. ASCI

字符编码 ASCII,Unicode 和 UTF-8 概念扫盲

今天中午,我突然想搞清楚Unicode和UTF-8之间的关系,于是就开始在网上查资料. 结果,这个问题比我想象的复杂,从午饭后一直看到晚上9点,才算初步搞清楚. 下面就是我的笔记,主要用来整理自己的思路.但是,我尽量试图写得通俗易懂,希望能对其他朋友有用.毕竟,字符编码是计算机技术的基石,想要熟练使用计算机,就必须懂得一点字符编码的知识. 1. ASCII码 我们知道,在计算机内部,所有的信息最终都表示为一个二进制的字符串.每一个二进制位(bit)有0和1两种状态,因此八个二进制位就可以组合出2

字符编码 ASCII,Unicode 和 UTF-8扫盲

今天中午,我突然想搞清楚Unicode和UTF-8之间的关系,于是就开始在网上查资料. 结果,这个问题比我想象的复杂,从午饭后一直看到晚上9点,才算初步搞清楚. 下面就是我的笔记,主要用来整理自己的思路.但是,我尽量试图写得通俗易懂,希望能对其他朋友有用.毕竟,字符编码是计算机技术的基石,想要熟练使用计算机,就必须懂得一点字符编码的知识. 1. ASCII码 我们知道,在计算机内部,所有的信息最终都表示为一个二进制的字符串.每一个二进制位(bit)有0和1两种状态,因此八个二进制位就可以组合出2

字符编码ASCII, Unicode和UTF-8

字符编码是计算机技术的基石,想要熟练使用计算机,就必须懂得一点字符编码的知识. 1. ASCII码 我们知道,在计算机内部,所有的信息最终都表示为一个二进制的字符串.每一个二进制位(bit)有0和1两种状态,因此八个二进制位就可以组合出256种状态,这被称为一个字节(byte).也就是说,一个字节一共可以用来表示256种不同的状态,每一个状态对应一个符号,就是256个符号,从0000000到11111111. 上个世纪60年代,美国制定了一套字符编码,对英语字符与二进制位之间的关系,做了统一规定

字符编码ascii、unicode、utf-&#173;‐8、gbk 的关系

ASIIC码: 计算机是美国人发明和最早使用的,他们为了解决计算机处理字符串的问题,就将数字字母和一些常用的符号做成了一套编码,这个编码就是ASIIC码.ASIIC码包括数字大小写字母和常用符号,一共128个,1字节(byte)=8bit,8bit能表示的最大数是256,所以ASIIC编码中一个字符的大小就是1个字节 Unicode编码: 计算机进入中国后,ASIIC完全不够用,于是我们就制定了自己的GB2312编码,把汉字编码了进去.类似的在各国都有相同的情况,各国都开始制定自己的一套编码,计