学习PHP中的字符串操作函数(一)

接下来的文章又是我们熟悉的内容了,也就是在 PHP 中关于字符串的操作相关的函数。相信不少函数都是大家每天都要接触的内容,不过也有一些函数可能并不是大家常见的,这里依然还是以学习了解为主。对于我们熟悉的内容,我们深入的看一下它的一些不太常用或者我们没有太注意过的参数,而对于不熟悉的内容,就来看看它的用法是怎样的,有什么好玩的地方。

PHP 中的字符串操作函数非常多,同时,还有一个非常大的问题,也是被很多人所诟病的问题,那就是 PHP 中的函数命名方式。比如有 str_replace() 这样下划线的,有 strstr() 这样啥都没有分隔的,这就让我们的记忆成本高了许多。而我们的文章也不是从单个的某个功能点出发,而是从这些命名格式来出发。比如我们今天这篇文章学习的是 strXXX 这些相关的函数,下篇文章学习 str_xxx 相关的以及带 _ 分割的一些字符串函数,最后一篇文章再学习其它剩下的函数。

好了,话不多说,我们直接进入主题吧。

替换字符串

首先就是我们非常常用的替换字符串。一说到这个,大家肯定第一个想到的就是 str_replace() ,但这个函数并不是我们今天的主题,在下篇文章中再讲它,今天我们要来学习的是其它的替换字符串功能的函数。

$str = "abcdefGHIjklMnOpQRSTUVWXYZabcdefGHIjklMnOpQRSTUVWXYZ";

// 替换1
echo strtr($str, 'abc', 'cba'), PHP_EOL; // cbadefGHIjklMnOpQRSTUVWXYZcbadefGHIjklMnOpQRSTUVWXYZ

$helloStr = "hi all, I said hello";
echo strtr($helloStr, ["hello" => "hi", "hi" => "hello"]), PHP_EOL; // hello all, I said hi 
echo str_replace(["hello", "hi"], ["hi", "hello"], $helloStr), PHP_EOL; // hello all, I said hello
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

strtr() 函数不知道大家有没有使用过。上面我们展示了它的替换操作的能力,也对比了和 str_replace() 的区别。大家能看出来区别所在吗?

对于单个字符串的替换来说,它和 str_replace() 的区别不大,可能比较明显的区别就是参数位置的不同而已。但在进行数组批量替换时,我们就能发现它们两个的显著的区别。对于字符串中的 hi 和 hello 来说,str_replace() 在这其中的效果是首先将 hello 替换成 hi ,然后数组中第二个又将 hi 替换成 hello ,最后的结果是字符串中只包含有 hello 。而 strtr() 则是以位移的形式来转换字符串,当第一个 hello 替换为 hi 的操作完成后,第二个 hi 替换 hello 的操作不会影响之前替换的结果,也就是像代码演示中的效果,我们原始字符串中的 hi 和 hello 调换了一个位置。

是不是感觉突然发现新大陆了,第一个函数就很有意思吧。

获取字符串

// 获取字符串
echo strtok($str, 'c'), PHP_EOL; // ab
echo strtok($str, 'H'), PHP_EOL; // abcdefG

echo strstr($str, "Mn"), PHP_EOL; // MnOpQRSTUVWXYZabcdefGHIjklMnOpQRSTUVWXYZ
echo strstr($str, "Mn", true), PHP_EOL; // abcdefGHIjkl

echo stristr($str, "mn"), PHP_EOL; // MnOpQRSTUVWXYZabcdefGHIjklMnOpQRSTUVWXYZ


echo strrchr($str, "Mn"), PHP_EOL; // MnOpQRSTUVWXYZ

echo strpbrk($str, "AVM"), PHP_EOL; // MnOpQRSTUVWXYZabcdefGHIjklMnOpQRSTUVWXYZ
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.

strtok() 是根据后面的第二个参数,也叫做 token 字符来获取字符串,并且获取到的是指定字符之前的字符串内容,这个函数不只是我们演示效果中的这么简单,它还有更强大的操作,大家可以自行去官方文档中了解。

strstr() 应该是稍微常见一点的函数,它是获取指定字符之后的所有字符串,不过如果增加第三个可选参数为 true 的话,那么它获取到的就是指定字符之前的内容。

strrchr() 是根据指定字符最后一次出现的位置获取之后的内容。strpbrk() 则是根据在指定字符内出现的任意一个字符,只要在原始字符串中出现的话,就获取其对应的之后的内容。

查找字符串位置

strpos() 相信大家一定不会陌生,这个函数也是很多面试时会问到的一个函数,至于对它来说会问什么问题呢?我们下面再说。

// 查找字符串位置

echo strspn($str, 'VWXYZabcde'), PHP_EOL; // 5
echo strspn("42 is the answer to the 128th question.", "1234567890 is "), PHP_EOL; // 6

echo strcspn($str, 'VWXYZabcde'), PHP_EOL; // 0
echo strcspn($str, 'VWXYZ'), PHP_EOL; // 21

echo strpos($str, 'cd'), PHP_EOL; // 2
echo strpos($str, 'abcd'), PHP_EOL; // 0
if(strpos($str, 'abcd')!==false){
    echo '存在!', PHP_EOL;
}
// 存在!

echo strpos($str, 'cd', 3), PHP_EOL; // 28

var_dump(strpos($str, 'vwx')); // bool(false)
echo stripos($str, 'vwx'), PHP_EOL; // 21

echo strrpos($str, 'abc'), PHP_EOL; // 26
echo strripos($str, 'vwx'), PHP_EOL; // 47
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.

首先来看到的是 strspn() 这个相对来说比较陌生的函数,它的作用是计算字符串中全部字符都存在于指定字符集合中的第一段子串的长度 。看不懂什么意思吧,那就看代码。在第一个测试语句中,VWXYZabcde 在原始的字符串中返回的是 5 ,表示的其实是 abcde 这 5 个字符和原始字符匹配上了。接下来的例子中,1234567890 is  和 42 is 匹配上了,算上空格的话正好返回的就是 6 。现在是不是搞明白了这个函数的作用了?当然,它并不常用,很可能我们现在看完了下次再看到它还是会懵圈,毕竟概念太复杂的函数应用场景还是比较有限的。

strcspn() 就是 strspn() 反过来的获取不匹配的结果数量。这个就不多做解释了。

接下来的是我们最常用的 strpos() 了,前面说过,面试时很多面试官喜欢问这个函数一个问题,那就是在 if 语句中如何判断它查找成功了。要知道,如果匹配的字符是字符串的第一个位置,那么它返回的结果是 0 。如果你回答使用 strpos() == false ,那么就错了哦,在比较运算符中,类型会强制转换的,这个在我们最早的文章中就学习过,所以 0 和 false 使用 == 的话会是相等的结果,但其实我们是匹配到字符了。所以,这时候我们就需要使用 === 来进行比较。当然,这个问题是比较初级的问题了,也是刚毕业的新手需要注意了解的一个问题。

strpos() 还有第三个参数,它是偏移量,也就是从第几个字符开始查找。stripos() 是忽略大小写的查找操作,strrpos() 是反过来从原始字符串的后面开始查找到最后一个匹配字符的位置,而 strripos() 就是忽略大小写的获取最后匹配字符位置的函数。

比较字符串

比较字符串,其实就像我们去对比两个字符 'a' > 'b' 一样,在内部大部分情况下其实都是转换成了 asc2 码来进行比较的。

var_dump(strcmp('Test', 'test')); // int(-32)
var_dump(strcmp('test', 'test')); // int(0)
var_dump(strcmp('test', 'Test')); // int(32)

var_dump(strcasecmp('Test', 'test')); // int(0)
var_dump(strcasecmp('Test', 'a test')); // int(19)

var_dump(strcmp('Test', 'Test a b', )); // int(-4)
var_dump(strncmp('Test', 'Test a b', 4)); // int(0)

var_dump(strncasecmp('Test', 'Test a b', 4)); // int(0)

var_dump(strcmp('test2.png', 'test10.png')); // int(1)
var_dump(strnatcmp('test2.png', 'test10.png')); // int(-1)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.

strcmp() 用于比较字符串,两个字符串如果相等返回的是 0 ,如果大于或者小于的话,返回的是它们的差值,也就是 asc2 码的差值。strcasecmp() 的作用和 stcmp() 是一样的,只是它是二进制安全地进行比较,strncmp()  则是比较开头的字符,strncasecmp() 在比较开头的几个字符时不区分大小写。

strnatcmp() 就比较有意思了,它是以自然语言的习惯来比较字符串,这里我们可以看到,在正常情况下 test2.png 从我们自然语言的角度来说应该是要小于 test10.png 的,但是在操作系统的文件夹排序中,test2 会排在 test10 之后,大家可以在自己电脑上试试。这就是机器比较算法和自然语言的区别,机器比较中是一个字符一个字符的比较,test10 在比较到那个 1 的时候,1 是比 2 小的,那么这时就会认为 test10 就会认为是比 test2 小的,在排序的时候自然也就排在 test2 前面了。而 strnatcmp() 则是以自然语言的方式来比较,我们再来一个典型的例子。

$arr1 = $arr2 = array("img12.png", "img10.png", "img2.png", "img1.png");
echo "Standard string comparison\n";
usort($arr1, "strcmp");
print_r($arr1);
// Standard string comparison
// Array
// (
//     [0] => img1.png
//     [1] => img10.png
//     [2] => img12.png
//     [3] => img2.png
// )

echo "\nNatural order string comparison\n";
usort($arr2, "strnatcmp");
print_r($arr2);
// Natural order string comparison
// Array
// (
//     [0] => img1.png
//     [1] => img2.png
//     [2] => img10.png
//     [3] => img12.png
// )
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.

这个例子使用的 usort() 函数,它的第二个参数可以接收一个回调函数用来确定比较的规则,这里我们直接使用 strnatcmp() 函数。是不是很明显就看到了结果的差异,上面使用 strcmp() 和我们操作系统中文件夹里面显示的排序结果是类似的,而下面的结果则更符合我们自然语言的排序结果。

其它

其它还有一些函数没有上面的函数那么复杂,我们也都了解一下。

字符串长度

这个想必不用多说,太常用了。

// 长度
echo strlen($str), PHP_EOL; // 52

$strC = "测试中文数据";
// 简单入门PHP中的多字节字符串操作
echo strlen($strC), PHP_EOL; // 18
echo mb_strlen($strC), PHP_EOL; // 6
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

需要注意的就是中文之类的多字节语言在 strlen() 中的表现,比较推荐的是使用 mb_strlen() 来操作中文字符,这个在之前的文章 简单入门PHP中的多字节字符串操作https://mp.weixin.qq.com/s/b3QyamwKngUz3OUQpf5VfQ 已经详细地讲解过,这里就不多说了。

大小写转换

同样非常常用的两个函数。

// 大小写
echo strtolower($str), PHP_EOL; // abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz
echo strtoupper($str), PHP_EOL; // ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ
  • 1.
  • 2.
  • 3.
转义斜杠
// 转义斜杠
$sql = "select * from a where a='1' and b = '2'";
echo addslashes($sql), PHP_EOL; // select * from a where a=\'1\' and b = \'2\'
echo stripcslashes(addslashes($sql)), PHP_EOL; // select * from a where a='1' and b = '2'
echo stripslashes(addslashes($sql)), PHP_EOL; // select * from a where a='1' and b = '2'
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

stripcslashes() 和 stripslashes() 都是用于反转义斜杠之类的字符串使用的,对于 addslashes() 来说,在早期的 mysql 扩展时代比较常用,现在用到的比较少了。它的反函数就是 stripcslashes() 。而 stripslashes() 通常来说就是针对斜杠的。

去除 html 和 php 标记
// 去除 html 和 php 标记
$text = '<p>Test paragraph.</p><!-- Comment --><?php echo 1;?> <br/><a href="#fragment">Other text</a>';
echo strip_tags($text), PHP_EOL;
// Test paragraph. Other text

echo strip_tags($text, '<br>'), PHP_EOL;
// Test paragraph. <br/>Other text
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

这个 strip_tags() 函数也是比较有意思的函数。它可以直接过滤掉我们字符串中的 HTML 和 PHP 相关的代码,它的第二个参数可以指定不过滤哪些标签。这个函数一般会在爬虫相关的应用中比较常见,比如我们之前做采集文章时需要文章的原文,也就是不带任何原始网站格式格式的纯文本,就会用到这个函数。

反转字符串

最后一个就非常简单了。

echo strrev($str), PHP_EOL; // ZYXWVUTSRQpOnMlkjIHGfedcbaZYXWVUTSRQpOnMlkjIHGfedcba
  • 1.

经常在面试的时候会要求写类似于这种反转字符串的算法,如果想耍点小聪明的话,可以直接用这个函数。当然,面试的时候如果面试官出这种题,那可能更看重的还是你的算法能力,尽量还是多自己研究一下这种反转的算法吧。

总结

今天的内容看着比较多,不过也只是冰山一角,字符串的操作函数库在任何语言中都是非常庞大的体系,接下来的学习任务还很重,不要错过后面的文章哦。

测试代码:

 https://github.com/zhangyue0503/dev-blog/blob/master/php/2021/03/source/7.%E5%AD%A6%E4%B9%A0PHP%E4%B8%AD%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%93%8D%E4%BD%9C%E5%87%BD%E6%95%B0%EF%BC%88%E4%B8%80%EF%BC%89.php

参考文档:

 https://www.php.net/manual/zh/ref.strings.php