共计 5128 个字符,预计需要花费 13 分钟才能阅读完成。
什么是多字节的字符串操作呢?其实不少的同学可能都曾经应用过了,但咱们还是要从最根底的问题说起。
一个字符占几个字节并不是咱们外表上看到的那样。失常状况下,一个数字或英文以及英文符号都是占用一个字节的。然而这个世界的语言文字何其之多,特地是像中文、日文这样的文字,往往用一个字节装不下,这时候就须要多字节来解决了(多字节个别第一个字节是前导字节示意以后是什么语言文字,前面的是正被的字节编码)。比如说一个中文字在 GBK 环境是占用两个字节,而在 UTF-8 下则是占用三个字节。而在最近几年,因为 emoji 表情的呈现 UTF-8MB4 又成为了支流,在示意这些 emoji 表情字符的时候,往往又会应用 UTF-8MB4 这种占用四个字节的编码格局来示意。
虽说字节的不同设置可能帮忙咱们展现丰盛的内容,但对它的一些操作却也带来了麻烦。
字符串操作
$str = "abc 测试一下";
echo strlen($str), PHP_EOL; // 15
strlen() 函数大家都不生疏,然而对于中文来说,它返回的数量显著是不对的。咱们以后默认的编码格局是 UTF-8,所以将一个中文当做三个英文字符来数就正好是 15 个字符长度。很显著,这不是咱们想要的后果,假如咱们要截取字符串的话,这个长度的计算可是很吃力的,搞不好还容易呈现乱码。
幸好在 PHP 的默认扩大中就曾经为咱们筹备好了一组 mb_ 函数库,专门用来解决这类多字节字符串的问题。
echo mb_strlen($str), PHP_EOL; // 7
echo mb_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) "一下"
当然,mb_ 相干的字符串操作函数是比拟全面的,字符呈现地位、大小写转换、截取字符串等函数都是提供的,调用的参数也都和一般的字符串操作函数没什么区别,只是它们多了一个可选的指定编码的参数。在通常的状况下,只有咱们的文件是对应的编码格局,这个参数就不必去写了。
当然,字符串的操作函数还有很多,这里就不一一列举了,大家能够自行查阅相干的文档。
字符串正则操作
既然说到了字符串的操作,正则相干的性能也是必不可少的,咱们先看下应用默认的 preg_ 相干的函数操作中文的问题。
$str = iconv('UTF-8', 'GB2312', $str);
var_dump(preg_match("/[a-z]* 测试 /i", $str)); // int(0)
var_dump(preg_replace("/[a-z]* 测试 /i","试试", $str)); // string(11) "abc����һ��"
首先咱们将测试用的字符串转换为 GB2312 的模式。就像咱们获取的内部接口可能返回的就是 GB2312 的编码的。这时间接应用 preg_ 相干的函数是无奈正确取得咱们想要的后果的。
mb_regex_encoding('GB2312');
$pattern = iconv('UTF-8', 'GB2312', "[a-z]* 测试");
var_dump(mb_ereg($pattern, $str)); // int(1)
var_dump(mb_eregi($pattern, $str)); // int(1)
var_dump(mb_ereg_replace($pattern,"试试", $str)); // string(10) "试试һ��"
var_dump(mb_eregi_replace($pattern,"试试", $str)); // string(10) "试试һ��"
接下来咱们通过 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',
// carrier:'�����ƶ�'
// }
var_dump(mb_convert_encoding($phone, 'UTF-8', "GBK"));
// string(183) "__GetZoneResult_ = {
// mts:'1388888',
// province:'云南',
// catName:'中国移动',
// telString:'13888888888',
// areaVid:'30515',
// ispVid:'3236139',
// carrier:'云南挪动'
// }
// "echo mb_detect_encoding($phone,'UTF-8,GBK'), PHP_EOL; // CP936
同样咱们还是拿这个获取手机号信息的公共接口测试,它返回的内容是 GBK 的编码内容。咱们能够通过 mb_convert_encoding() 来转换它的编码内容。mb_detect_encoding() 是检测编码格局,这里咱们给了两个参数,它会返回符合条件的编码内容,CP936 就是 GBK 的另一种示意(IBM 在制作 code page 时将 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);
// Array
// (// [a] => 我上
// )
首先咱们运行起来测试文件,而后用浏览器申请这个链接地址。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) "no overload"
// ["mail_charset"]=>
// string(5) "UTF-8"
// ["mail_header_encoding"]=>
// string(6) "BASE64"
// ["mail_body_encoding"]=>
// string(6) "BASE64"
// ["illegal_chars"]=>
// int(0)
// ["encoding_translation"]=>
// string(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
各自媒体平台均可搜寻【硬核项目经理】