什么是多字节的字符串操作呢?其实不少的同学可能都已经使用过了,但我们还是要从最基础的问题说起。

一个字符占几个字节并不是我们表面上看到的那样。正常情况下,一个数字或英文以及英文符号都是占用一个字节的。但是这个世界的语言文字何其之多,特别是像中文、日文这样的文字,往往用一个字节装不下,这时候就需要多字节来解决了(多字节一般第一个字节是前导字节表示当前是什么语言文字,后面的是正被的字节编码)。比如说一个中文字在 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/zhangyue0503/dev-blog/blob/master/php/202011/source/10.简单入门PHP中的多字节字符串操作.php][https://github.com/zhangyue0503/dev-blog/blob/master/php/202011/source/10.简单入门PHP中的多字节字符串操作.php]

参考文档:

https://www.php.net/manual/zh/book.mbstring.php

关注公众号:【硬核项目经理】获取最新文章

添加微信/QQ好友:【xiaoyuezigonggong/149844827】免费得PHP、项目管理学习资料

知乎、公众号、抖音、头条搜索【硬核项目经理】

B站ID:482780532

简单入门PHP中的多字节字符串操作的更多相关文章

  1. JavaScript中常见的字符串操作函数及用法

    JavaScript中常见的字符串操作函数及用法 最近几次参加前端实习生招聘的笔试,发现很多笔试题都会考到字符串的处理,比方说去哪儿网笔试题.淘宝的笔试题等.如果你经常参加笔试或者也是一个过来人,相信 ...

  2. LoadRunner中常用的字符串操作函数

    LoadRunner中常用的字符串操作函数有:                strcpy(destination_string, source_string);               strc ...

  3. Bash 中常见的字符串操作

    获取字符串长度 ${#string} MyString=abcABC123ABCabc 注意这会自动去掉字符串结尾处的空格,如果在字符串中包含空格(开头.中间或结尾),就需要使用引号把字符串包裹起来: ...

  4. PHP开发中常用的字符串操作函数

    1,拼接字符串 拼接字符串是最常用到的字符串操作之一,在PHP中支持三种方式对字符串进行拼接操作,分别是圆点.分隔符{}操作,还有圆点等号.=来进行操作,圆点等号可以把一个比较长的字符串分解为几行进行 ...

  5. js String对象中常用方法小结(字符串操作)

    1.charCodeAt方法返回一个整数,代表指定位置字符的Unicode编码. strObj.charCodeAt(index) 说明: index将被处理字符的从零开始计数的编号.有效值为0到字符 ...

  6. C语言中常用的字符串操作函数

    程序开头要声明 #include <string.h> 函数名: stpcpy 功 能: 拷贝一个字符串到另一个 用 法: char *stpcpy(char *destin, char ...

  7. 深圳尚学堂:JavaScript中常见的字符串操作

    快到春节放假了,春节后又是一大波的找工作热潮,在前端实招聘笔试时,必不可免额会考到关于JavaScript中字符串的处理问题.考的不是你会不会,而是你能不能在不借用XX手册或者XX指南再或者百度谷歌的 ...

  8. Java中的字符串操作(比较String,StringBuiler和StringBuffer)

    一.前言 刚开始学习Java时,作为只会C语言的小白,就为其中的字符串操作而感到震撼.相比之下,C语言在字节数组中保存一个结尾的\0去表示字符串,想实现字符串拼接,还需要调用strcpy库函数或者自己 ...

  9. PHP字符串操作汇总

    PHP开发中常用的字符串操作介绍 -- 简明现代魔法 PHP学习笔记之字符串的简单处理 - RuanJava的专栏 - 博客频道 - CSDN.NET PHP String 函数

随机推荐

  1. Golang语言系列-03-流程控制语句

    Go语言流程控制语句 Go语言中最常用的流程控制语句有 if 和 for ,没有像Python中的while语句.另外,Go语言还有switch和goto语句,不过这两个主要是用来简化代码的,属于扩展 ...

  2. 【笔记】衡量线性回归法的指标 MSE,RMS,MAE以及评价回归算法 R Square

    衡量线性回归法的指标 MSE,RMS,MAE以及评价回归算法 R Square 衡量线性回归法的指标 对于分类问题来说,我们将原始数据分成了训练数据集和测试数据集两部分,我们使用训练数据集得到模型以后 ...

  3. SIM900A—发送、接收中英文短信

    文章目录 一.SMS简介 二.短信的控制模式与编码 1.Text Mode 2.PDU Mode 3.GSM编码 4.UCS2编码 三.收发英文短信 1.AT+CPMS查询短信数量 2.AT+CNMI ...

  4. MySQL Mac 终端环境变量配置

    MySQL Mac 终端环境变量配置 这里安装的是mysql-8.0.26-macos11-x86_64,M1Mac,原本打算安装arm64版本,但一直安装不了,就装了x86版本 安装完成MySQL之 ...

  5. iNeuOS工业互联平台,聚合和变化率计算、设备IO和通讯状态、组态快捷键、创建文件夹、选择应用图标等,发布:v3.6版本

    目       录 1.      概述... 2 2.      平台演示... 2 3.      聚合和变化率计算... 2 4.      设备IO和通讯状态监测... 3 5.      组 ...

  6. Java之Spring基础与IoC

    Spring About Spring 开源免费框架,轻量级,非入侵式框架.Spring就是一个轻量级的控制反转(IOC)和面向切片编程(AOP)的框架 Maven repo:Spring Web M ...

  7. 如何在github上传本地项目代码

    首先你要在github上申请一个账号 网址:https://github.com/ 然后你要下载一个git工具 网址:https://gitforwindows.org/ 进入官网直接下载就行,下载完 ...

  8. 【ArcGIS】 设置管段的流向

    在排水管网或者燃气管网中对管段进行几何网络分析,常常用到设置管段流向,一般有三种方法: 1,有流向字段的,直接进行唯一值渲染, 2,没有流向字段的需要建立几何网络, 2.1 在几何网络存在的情况下,设 ...

  9. mzy对于枚举的理解

    关于enum,其实就是简化了的class,功能就是提供一个个独立的.特定含义的常量! 在JDK5.0之前我们想模拟enum的功能,只能使用自定义类的形式: 1.首先私有化构造方法,让外部不能new对象 ...

  10. 使用filter过滤GZIP压缩(二)

    在代码之前,讲一下用filter实现GZIP压缩的原理: 因为GZIP压缩之后,是从服务器端传输到浏览器端,从servlet到浏览器(从jsp到浏览器),其实是response带回内容,所以我们要在f ...