php 提示宽输出,php 中的宽字符处理

编码问题简述

ASCII编码,ASCII(American Standard Code for Information Interchange),是一种字符编码标准,它的字符集为英文字符集,它规定字符集中的每个字符均由一个字节表示,指定了字符表编码表,称为ASCII码表。这是最开始的编码。

ANSI编码,ASCII码只满足了英文国家的需求,对于汉语日语什么的没有考虑。于是各个国家纷纷制定了适用于自己国家的编码,GB2312、BIG5、JIS等仅适用于本国字符集的编码标准。这些字符编码标准统称为ANSI编码标准,而ANSI编码一般是兼容ASCII编码的。

例如,GBK的中文编码是双字节来表示的,英文编码是用ascii码表示的,既用单字节表示。但GBK编码表中也有英文字符的双字节表示形式,所以英文字母可以有两种GBK表示方式。为区分中文,将其最高位都定成1。英文单字节最高位都为0。当用GBK解码时,若高字节最高位为0,则用ASCII码表解码;若高字节最高位为1,则用GBK编码表解码。

但是各个国家的ANSI编码相互之间是不兼容的。于是UNICODE出现了。

UNICODE编码,简单的说,UNICODE可以把各个国家的语言文字和各种符号都包含进去,相互之间也就不需要转码了(理想情况)。但是UNICODE只是码表,具体到码字的具体编码形式,则又出现了UTF。

UTF(Unicode Translation Format),它是Unicode (UCS)的实现(或存储)方式,称为Unicode转换格式。Unicode 的实现方式不同于编码方式。一个字符的 Unicode 编码是确定的。但是在实际传输过程中,由于不同系统平台的设计不一定一致,以及出于节省空间的目的,对 Unicode 编码的实现方式有所不同。

UTF有三种实现方式:

UTF-16:其本身就是标准的Unicode编码方案,又称为UCS-2,它固定使用16 bits(两个字节)来表示一个字符。由于固定使用两个字节,UTF-16是不能完全表示UNICODE的,使用2字节的只是一部分UNICODE,很多辅助平面的UNICODE需要3-4个字节才能表示。

UTF-32:又称为UCS-4,它固定使用32 bits(四个字节)来表示一个字符。

UTF-8:最广泛的使用的UTF方案,UTF-8使用可变长度字节来储存Unicode字符,例如ASCII字母继续使用1字节储存,重音文字、希腊字母或西里尔字母等使用2字节来储存,而常用的汉字就要使用3字节。辅助平面(UNICODE分为好多平面)字符则使用4字节。UTF-8更便于在使用Unicode的系统与现存的单字节的系统进行数据传输和交换。与前两个方案不同:UTF-8以字节为编码单元,没有字节序的问题。

UTF-8的编码形式:

0000 - 007F 这部分是最初的ascii部分,按原始的存储方式,即0xxxxxxx。

0080 - 07FF 这部分存储为110xxxxx 10xxxxxx

0800 - FFFF 这部分存储为1110xxxx 10xxxxxx 10xxxxxx

可以看到,UTF-8也是兼容ASCII的。

由于UTF-8和GBK都是兼容ASCII的,所以在编辑器切换这两种编码方式的时候,英文的显示是不受影响的。

GBK,GB2312以及Unicode都既是字符集,也是编码方式,而UTF-8只是编码方式,并不是字符集。

PHP中宽字符的处理

这里把ASCII以外的编码表示的字符都称为宽字符。php提供了丰富的函数处理ASCII字符。对于宽字符的处理,则是依靠mbstring这个扩展提供的一系列扩展函数实现的。

例如字符长度的计算是通过mb_strlen实现的:

$str='中文a字1符';

echo strlen($str); //字节个数,14

echo mb_strlen($str,'UTF-8'); //选定内码为UTF-8,中文作为一个字节,6

echo mb_strlen($str,'gbk'); //8

echo mb_strlen($str,'gb2312'); //10

这是网上的一个文章中的例子。mb_strlen的第二个参数就是用来指明$str的所使用的编码的,而不是要求函数以某种编码方式计算长度。

$str中字串的编码方式就是当前脚本文件的编码方式(这里是UTF-8),所以只有mb_strlen($str,'UTF-8')得出正确结果。不知道为什么这种明显的错误在网上不止一处的文章里出现。

mb_strlen的函数原型:

mixed mb_strlen ( string $str [, string $encoding = mb_internal_encoding() ] )

第二个参数默认是mb_internal_encoding(),需要注意的是mb_internal_encoding()一般并不和当前的脚本文件的编码方式相同,脚本最常用的是UTF-8,没有更改设置的情况下mb_internal_encoding()一般是ISO-8859-1,也就是Latin-1编码。

脚本文件的编码和mb_internal_encoding()没有必要一致,进行相关处理的处理的时候指明参数的正确编码方式就行,比如这里的mb_strlen。有的时候可能没有机会设置这个参数,出现乱码的时候,可以考虑下是不是这里的问题。

其他常用的函数还有:

mb_​convert_​encoding (容易出危险的函数)

mb_​ereg_​replace_​callback (也是容易出危险的函数)

mb_​split

mb_​substr

等等。

网页的乱码

为了防止网页出现乱码,概括说来,做到以下四点就好了:

PHP脚本文件本身使用UTF-8字符集。

网页使用utf-8编码。

MySQL数据库使用utf8字符集。

各类字符串操作使用Multibyte String系列函数。

这只是一个简略的概括,更多信息可以参考其他文章。

和操作系统的交互

操作系统(这里说windows)的API也是有编码的问题的。就像大家都知道的,UNICODE出来之前,操作系统通过内码来确定相应的ANSI代码页以处理不同的语言。UNICODE出来后,则定义了另一套的函数。例如MessageBox函数,有两个版本:

MessageBoxA

MessageBoxW

A代表ANSI代码页,W是宽字符,即Unicode字符。Windows中的Unicode字符一般指UCS2的UTF16-LE编码。(这里称为宽字符有些莫名其妙的感觉,相对于单字节的ASCII来说,ANSI编码也是宽的。。)

编译时通过预定义宏来决定具体使用哪一个函数。但是系统的内核是UNICODE的,所有A系列函数最后都会转化为对W函数的调用。

相应的,运行时库的函数也是有两个版本函数的。

那么需要调用操作系统的功能,比如打开一个文件的时候:

$filename = “我的文件.txt”;

//$filename = iconv(‘UTF-8’,’GBK’, $filename);//转换为GBK编码

$file_handler = fopen($filename);

脚本文件的编码是UTF-8,那么这里打开会失败,需要转换为GBK编码。没有去看fopen的源码,但是这里应该是调用c运行时库的A版本的函数。

那么php有没有使用宽字符的版本呢?文档里没找到,但是即使有的话,调用之前也得转化为UTF16-LE编码再调用。和A版本的函数一样麻烦(转换一下也不是很麻烦)。

PHP-cli程序从命令行获得字符串是什么编码呢?自然是和系统的当前代码页一致的ANSI编码。

另外,读取utf8的文件的时候要注意,开始的第一行可能是三个不可见的字符:

ef bb bf

也就是BOM,注意处理,免得出问题。

参考:

标签:字符,编码,UTF,字节,mb,处理,php,ASCII

来源: https://www.cnblogs.com/robotech/p/11094978.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值