什么是多字节字符串操作?其实很多同学可能已经用过了,但是我们还是要从最基础的问题入手。一个字符占用多少字节并不是我们表面上看到的。一般情况下,一个数字或英文和英文符号占用一个字节。但是这个世界上有那么多的语言和文字,尤其是像中文、日文这样的文字,往往一个字节都装不下。这时候就需要多字节来解决问题了(多字节一般以第一个字节为前导字节表示当前的语言文字,后面是正在编码的字节编码)。比如一个汉字在GBK环境下占两个字节,在UTF-8环境下占三个字节。近年来,由于emoji表情的出现,UTF-8MB4再次成为主流。在表达这些emoji字符时,常用UTF-8MB4,以四字节的编码格式来表达。字节的不同设置虽然可以帮助我们展示丰富的内容,但是对它的一些操作也带来了麻烦。字符串操作$str="abctest";echostrlen($str),PHP_EOL;//15strlen()函数大家都很熟悉,但是对于中文来说,它返回的数字显然是错误的。我们目前默认的编码格式是UTF-8,所以一个中文算三个英文字符正好是15个字符。显然,这不是我们想要的结果。如果我们要截取字符串,这个长度的计算是非常费力的,而且可能容易出现乱码。好在PHP默认的扩展中已经为我们准备了一套mb_函数库,专门用来处理这种多字节字符串的问题。echomb_strlen($str),PHP_EOL;//7echomb_strlen($str,'GB2312'),PHP_EOL;//11如果不指定mb_strlen()函数的第二个参数,会按照当前文档默认的编码格式进行转换,所以我们的字符串长度在UTF-8环境下是正常显示的。当然,我们也可以指定第二个参数为另一种编码格式,比如以前常用的GB2312或者GBK,这样返回的字符长度是以一个汉字占用两个字节的形式返回的。var_dump(mb_strpos($str,“测试”));//int(3)var_dump(mb_convert_case($str,MB_CASE_UPPER));//string(15)"ABC测试"var_dump(mb_convert_case($str,MB_CASE_LOWER));//string(15)"Abc测试"var_dump(mb_substr($str,5));//string(6)"Test"当然,mb_相关的字符串操作函数比较全面,字符出现位置,大小写转换,字符串截取等函数都提供了,调用的参数也和普通的没什么区别字符串操作函数,除了它们有一个用于指定编码的可选参数。一般情况下,只要我们的文件是相应的编码格式,这个参数就不需要写了。当然,字符串操作函数还有很多,这里就不一一列举了。可以自行查阅相关文档。字符串正则化操作说到字符串操作,正则化相关的函数也是必不可少的。我们先来看使用默认的preg_相关函数操作中文的问题。$str=iconv('UTF-8','GB2312',$str);var_dump(preg_match("/[a-z]*test/i",$str));//int(0)var_dump(preg_replace("/[a-z]*Test/i","Try",$str));//string(11)"abc???????"首先,我们将测试字符串转换为GB2312格式。就像我们获取到的对外接口可能会返回GB2312的编码。这时候直接使用preg_相关函数是无法正确得到我们想要的结果的。mb_regex_encoding('GB2312');$pattern=iconv('UTF-8','GB2312',"[a-z]*test");var_dump(mb_ereg($pattern,$str));//int(1)var_dump(mb_eregi($pattern,$str));//int(1)var_dump(mb_ereg_replace($pattern,"Try",$str));//string(10)"Try????"var_dump(mb_eregi_replace($pattern,"Try",$str));//string(10)"Try¥??"接下来,我们使用mb_ereg相关的函数进行正则匹配和替换,就可以正常对不同编码的字符串进行操作了。注意我们需要指定mb_regex_encoding()函数来告诉当前默认的规划替换编码为GB2312,同时正则也需要转换成对应的编码格式。mb_eregi相关函数和mb_ereg其实没有本质区别,只是不区分大小写,就像我们在preg相关函数中写正则表达式时的后缀符号i一样。ereg相关的函数不用写反斜杠。其实都是普通函数中被淘汰的函数(性能不如preg,语法也不一样)。大多数情况下,会直接使用preg相关的函数。操作。但是,如果涉及到多字节相关的问题,mb_函数库中只能使用ereg等函数。字符串编码转换就像我们之前学习的iconv()函数一样,mb_库也提供了字符编码转换的函数。$phone=file_get_contents('https://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel=13888888888');print_r($phone);//__GetZoneResult_={//mts:'1388888',//province:'????',//catName:'??й?????',//telString:'13888888888',//areaVid:'30515',//ispVid:'3236139',//运营商:'???????'//}var_dump(mb_convert_encoding($phone,'UTF-8',"GBK"));//string(183)"__GetZoneResult_={//mts:'1388888',//province:'云南',//catName:'中国移动',//telString:'13888888888',//areaVid:'30515',//ispVid:'3236139',//carrier:'云南移动'//}//"echomb_detect_encoding($phone,'UTF-8,GBK'),PHP_EOL;//对于CP936,我们还是使用这个公共接口来测试电话号码信息,返回的内容是GBK编码后的内容。我们可以通过mb_convert_encoding()对其编码内容进行转换。mb_detect_encoding()是检测编码格式,这里我们给两个参数,它会返回符合条件的编码内容,CP936是GBK的另一种表示(IBM在做代码页的时候把GBK编码放在了936页)。HTTP参数操作mb_internal_encoding("UTF-8");首先介绍一个mb_internal_encoding()函数,它实际上是设置当前运行环境中的默认编码规则。如果不设置,默认使用当前php文件的编码规则。大家明白,因为会影响我们后面介绍的内容。////localhost:9991/?a=我在var_dump(mb_http_input('GPC'));//bool(false)var_dump(mb_http_output());//string(5)"UTF-8"mb_internal_encoding("CP936");mb_parse_str($_SERVER['QUERY_STRING'],$result);print_r($result);//数组//(//[a]=>Igo//)首先我们运行测试文件,然后使用浏览器请求这个链接地址。mb_http_input()检测HTTP输入字符编码,但我的测试结果都返回false。有知情者可以留言说明是怎么回事。而mb_http_output是设置检测输出的编码,会受mb_internal_encoding()定义的内容影响。此外,mb_parse_str()是parse_str()函数的多字节版本。我们可以将浏览器的默认编码转换为GBK或者稍后请求,因为我们设置了当前的mb_internal_encoding()为CP936。默认情况下,如果使用UTF-8的浏览器请求,这里会报错,就是mb_internal_encoding()对这些函数的影响。查看其他属性最后,我们看一下一些mb_相关信息属性的内容。var_dump(mb_language());//string(7)"neutral"mb_language()函数用于获取/设置当前语言,它可以接收一个参数来设置当前语言信息。主要用于对邮件信息进行编码mb_send_mail()函数使用它对邮件进行编码。关于mb_send_mail()的使用,大家可以自己尝试一下。事实上,它也是send_mail()函数的多字节版本。Neutral就是中立的意思,其实和我们的mb_internal_encoding()有关。var_dump(mb_list_encodings());//array(86){//[0]=>//string(4)"pass"//[1]=>//string(5)"wchar"//[2]=>//string(7)"byte2be"//[3]=>//...//[65]=>//string(5)"CP936"//...使用了mb_list_encodings()显示当前系统支持的所有语言代码的列表,在这个列表中我们可以看到CP936,但是没有GBK,记住它们是一回事。var_dump(mb_get_info());//array(14){//["internal_encoding"]=>//string(5)"UTF-8"//["http_output"]=>//string(5)"UTF-8"//["http_output_conv_mimetypes"]=>//string(31)"^(text/|application/xhtml\+xml)"//["func_overload"]=>//int(0)//["func_overload_list"]=>//string(11)"nooverload"//["mail_charset"]=>//string(5)"UTF-8"//["mail_header_encoding"]=>//string(6)"BASE64"//["mail_body_encoding"]=>//string(6)"BASE64"//["illegal_chars"]=>//int(0)//["encoding_translation"]=>//字符串(3)"Off"//["language"]=>//string(7)"neutral"//["detect_order"]=>//array(2){//[0]=>//string(5)"ASCII"//[1]=>//string(5)"UTF-8"//}//["substitute_character"]=>//int(63)//["strict_detection"]=>//string(3)"Off"//}mb_get_info()是查看当前环境下这些语言编码的默认配置,比如我们熟悉的可以在此处看到internal_encoding和http_output属性。用过的同学是不是也发现了今天这篇文章的新姿势呢?没错,GBK和CP936就成了今天这篇文章中意想不到的惊喜。之前真的没有注意到这一点。其实mb_相关函数的使用非常普遍,基本是学习PHP必备的知识。它还有很多功能没有一一列举。有兴趣的同学可以参考官方手册进行更深入的学习。测试代码:https://github.com/zhangyue05...PHP多字节字符串操作简单介绍。php参考文档:https://www.php.net/manual/zh/book.mbstring.php各媒体平台均可搜索【硬核项目经理】
