Skip to content

常用字符串函数

概述

PHP 提供了丰富的内置字符串处理函数,涵盖长度计算、截取、查找、替换、大小写转换、填充、分割等多个方面。本章对这些常用函数进行系统分类讲解,并提供实际使用示例。

基础概念

函数分类一览

分类函数说明
长度计算strlen, mb_strlen获取字符串长度
截取substr, mb_substr截取子字符串
查找strpos, strrpos, strripos, strstr查找子串位置
替换str_replace, substr_replace替换子字符串
大小写strtolower, strtoupper, ucfirst, lcfirst, ucwords大小写转换
空白处理trim, ltrim, rtrim去除空白字符
填充str_pad, str_repeat字符串填充和重复
分割chunk_split, wordwrap字符串分割
反转strrev字符串反转
随机str_shuffle随机打乱字符

语法与代码

长度与截取

php
<?php

declare(strict_types=1);

// strlen - 获取字符串字节长度
echo strlen('Hello');           // 5
echo strlen('你好');            // 6(UTF-8 中每个中文 3 字节)

// substr - 截取子字符串
echo substr('Hello, World!', 0, 5);    // Hello
echo substr('Hello, World!', 7);       // World!
echo substr('Hello, World!', -6);      // orld!
echo substr('Hello, World!', -6, -1);  // orld

// substr 作为数组访问的安全替代
$str = 'Hello';
echo substr($str, 0, 1);     // H(等同于 $str[0],但更安全)
echo substr($str, -1);       // o(最后一个字符)

查找函数

php
<?php

declare(strict_types=1);

// strpos - 查找子串首次出现的位置(区分大小写)
$haystack = 'Hello, World!';
echo strpos($haystack, 'World');      // 7
echo strpos($haystack, 'world');      // false(区分大小写)

// stripos - 不区分大小写的查找
echo stripos($haystack, 'WORLD');     // 7

// strrpos - 查找子串最后出现的位置
echo strrpos('abcabcabc', 'abc');     // 6
echo strripos('abcABCabc', 'ABC');    // 6(不区分大小写)

// strstr - 返回从匹配位置开始的子字符串
echo strstr('Hello, World!', 'World');    // World!
echo strstr('Hello, World!', 'World', true); // Hello, (返回匹配之前的部分)

// 注意:strpos 返回 false 或 0,必须用 === 比较
if (strpos($haystack, 'Hello') === 0) {
    echo '以 Hello 开头';
}

替换函数

php
<?php

declare(strict_types=1);

// str_replace - 替换所有匹配的子字符串
$text = 'Hello, World! Hello, PHP!';
echo str_replace('Hello', 'Hi', $text);   // Hi, World! Hi, PHP!

// str_ireplace - 不区分大小写的替换
echo str_ireplace('hello', 'Hi', $text);  // Hi, World! Hi, PHP!

// 数组批量替换
$replace = ['Hello' => 'Hi', 'World' => 'Earth', 'PHP' => 'Code'];
echo str_replace(array_keys($replace), array_values($replace), $text);

// str_replace 统计替换次数(PHP 8.0+)
$count = 0;
str_replace('Hello', 'Hi', $text, $count);
echo $count;  // 2

// substr_replace - 基于位置替换
echo substr_replace('Hello, World!', 'PHP', 7, 5);  // Hello, PHP!

// 删除子字符串
echo str_replace('World', '', $text);  // Hello, ! Hello, !

大小写转换

php
<?php

declare(strict_types=1);

// strtolower - 转为小写
echo strtolower('Hello WORLD');    // hello world

// strtoupper - 转为大写
echo strtoupper('hello world');    // HELLO WORLD

// ucfirst - 首字母大写
echo ucfirst('hello world');       // Hello world

// lcfirst - 首字母小写
echo lcfirst('Hello World');      // hello World

// ucwords - 每个单词首字母大写
echo ucwords('hello world php');  // Hello World Php

// mb_convert_case - 多字节安全的大小写转换
echo mb_convert_case('hello WORLD', MB_CASE_TITLE, 'UTF-8');  // Hello World

// 注意:默认大小写转换只对 ASCII 字符有效
echo strtoupper('café');           // Déjà 被处理为 CAFé(部分字符不转换)
echo strtoupper('café');           // 需要 mb_strtoupper
echo mb_strtoupper('café', 'UTF-8');  // Déjà -> CAFé -> 正确: CAFÉ

空白处理与填充

php
<?php

declare(strict_types=1);

// trim - 去除两端空白字符(空格、制表符、换行等)
echo trim('  hello  ');           // hello
echo trim("\t\n hello \n\t");     // hello

// ltrim / rtrim - 去除左/右侧空白
echo ltrim('  hello');            // hello
echo rtrim('hello  ');            // hello

// trim 也可以去除指定字符
echo trim('***hello***', '*');    // hello

// str_pad - 字符串填充
echo str_pad('42', 8, '0', STR_PAD_LEFT);   // 00000042
echo str_pad('42', 8, '-');                 // 42------
echo str_pad('42', 8, '-', STR_PAD_BOTH);   // ---42---

// str_repeat - 重复字符串
echo str_repeat('ab', 3);          // ababab
echo str_repeat('-', 40);         // ----------------------------------------

分割与换行处理

php
<?php

declare(strict_types=1);

// chunk_split - 按固定长度分割字符串
echo chunk_split('ABCDEFGH', 2, '-');    // AB-CD-EF-GH-
echo chunk_split('1234567890', 4, ' '); // 1234 5678 90

// wordwrap - 按单词边界换行
$text = 'The quick brown fox jumps over the lazy dog.';
echo wordwrap($text, 20, "\n");         // 每 20 个字符换行
echo wordwrap($text, 20, '<br>');       // HTML 换行

// explode / implode - 字符串分割与连接
$fruits = 'apple,banana,cherry';
$arr = explode(',', $fruits);           // ['apple', 'banana', 'cherry']
echo implode(' | ', $arr);              // apple | banana | cherry

// explode 限制分割数量
$parts = explode(',', 'a,b,c,d,e', 3);  // ['a', 'b', 'c,d,e']

反转与随机

php
<?php

declare(strict_types=1);

// strrev - 反转字符串(注意:对多字节字符不安全)
echo strrev('Hello');           // olleH
echo strrev('你好');             // 好你(仅适用于 GBK 等双字节编码,UTF-8 会乱码)

// str_shuffle - 随机打乱字符顺序
$str = 'abcdef';
echo str_shuffle($str);          // 例如: dbfcea(每次结果不同)

// 应用:生成随机验证码
function generateCode(int $length = 6): string
{
    $chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    return substr(str_shuffle(str_repeat($chars, (int)ceil($length / strlen($chars)))), 0, $length);
}

echo generateCode(6);            // 例如: xK9mQ2

详细说明

函数参数类型

PHP 8.0+ 参数类型改进

PHP 8.0 以后,许多字符串函数对 null 参数的处理更加严格。例如 strlen(null) 在 PHP 7.4 返回 0,在 PHP 8.0+ 抛出 TypeError。

str_replace vs preg_replace

特性str_replacepreg_replace
匹配方式固定字符串正则表达式
性能更快较慢
灵活性
批量替换支持数组支持数组
计数PHP 8.0+ 通过第 4 参数通过第 5 参数

strpos 返回值陷阱

php
<?php

declare(strict_types=1);

$str = 'Hello, World!';

// 错误:strpos 在位置 0 找到时,0 == false 为真
if (strpos($str, 'Hello')) {
    // 不会执行!因为 strpos 返回 0
}

// 正确:使用严格比较
if (strpos($str, 'Hello') !== false) {
    echo '找到了';
}

// PHP 8.0+ 更好的替代方案
if (str_contains($str, 'Hello')) {
    echo '找到了';
}

实战示例

URL 规范化

php
<?php

declare(strict_types=1);

function normalizeUrl(string $url): string
{
    $url = strtolower($url);
    $url = trim($url);
    $url = preg_replace('#^https?://#', '', $url);
    $url = rtrim($url, '/');

    return 'https://' . $url;
}

echo normalizeUrl('  HTTP://Example.COM/path/  ');
// 输出: https://example.com/path

CSV 数据解析

php
<?php

declare(strict_types=1);

function parseSimpleCsv(string $csvLine): array
{
    $csvLine = trim($csvLine);
    $fields = [];

    foreach (explode(',', $csvLine) as $field) {
        $field = trim($field);
        $fields[] = trim($field, '"\'');
    }

    return $fields;
}

$data = '"Alice",30,"Developer"';
print_r(parseSimpleCsv($data));
// ['Alice', '30', 'Developer']

文件扩展名处理

php
<?php

declare(strict_types=1);

function getExtension(string $filename): string
{
    return strtolower(substr(strrchr($filename, '.'), 1));
}

function removeExtension(string $filename): string
{
    $pos = strrpos($filename, '.');
    return $pos !== false ? substr($filename, 0, $pos) : $filename;
}

echo getExtension('photo.JPG');      // jpg
echo getExtension('archive.tar.gz');  // gz
echo removeExtension('document.pdf'); // document

字符串函数完整分类表

截取与查找

函数说明多字节安全
substr($str, $start, $len)截取子字符串
mb_substr($str, $start, $len, $enc)多字节截取
strstr($haystack, $needle)返回 needle 首次出现到末尾
stristr($haystack, $needle)不区分大小写版本
strrchr($haystack, $needle)返回 needle 最后出现到末尾
strpbrk($haystack, $charList)返回包含 charList 中任一字符的位置
substr_count($haystack, $needle)统计子串出现次数
substr_replace($str, $replace, $start, $len)基于位置替换N/A
chunk_split($str, $len, $end)按长度分割并加后缀N/A

编码转换

php
<?php

declare(strict_types=1);

// 字符串编码相关
echo ord('A');            // 65(获取字符 ASCII 码)
echo chr(65);             // A(ASCII 码转字符)
echo bin2hex('Hello');    // 48656c6c6f
echo hex2bin('48656c6c6f'); // Hello
echo base64_encode('Hello'); // SGVsbG8=
echo base64_decode('SGVsbG8='); // Hello
echo urlencode('Hello World');   // Hello+World
echo urldecode('Hello+World');   // Hello World
echo rawurlencode('Hello World'); // Hello%20World
echo nl2br("Line1\nLine2"); // Line1<br>Line2

// quoted_printable_encode/decode - 用于邮件编码
$encoded = quoted_printable_encode('你好');
$decoded = quoted_printable_decode($encoded);

// convert_uuencode/convert_uudecode - UU 编码
$encoded = convert_uuencode('Hello');
$decoded = convert_uudecode($encoded);

字符串比较

php
<?php

declare(strict_types=1);

// strcmp - 区分大小写的字符串比较
echo strcmp('abc', 'abc');    // 0(相等)
echo strcmp('abc', 'abd');    // -1(小于)
echo strcmp('abd', 'abc');    // 1(大于)

// strcasecmp - 不区分大小写
echo strcasecmp('ABC', 'abc'); // 0

// strncmp - 比较前 n 个字符
echo strncmp('abcde', 'abcxy', 3); // 0(前3个字符相同)

// strnatcmp - 自然顺序比较
echo strnatcmp('img2.png', 'img10.png');  // -1(2 < 10)
echo strcmp('img2.png', 'img10.png');    // 1('2' > '1')

// strcoll - 基于区域设置的字符串比较
$locale = setlocale(LC_COLLATE, 'zh_CN.UTF-8');
echo strcoll('中', '英');  // 比较结果取决于区域设置

// similar_text - 计算两个字符串的相似度
similar_text('Hello World', 'Hello PHP', $percent);
echo $percent;  // 相似度百分比

常用字符串工具函数

php
<?php

declare(strict_types=1);

// 判断是否为 JSON 字符串
function isJson(string $str): bool
{
    json_decode($str);
    return json_last_error() === JSON_ERROR_NONE;
}

// 生成随机字符串
function randomString(int $length = 16): string
{
    return substr(bin2hex(random_bytes($length)), 0, $length);
}

// 字符串截断(不截断单词)
function truncateWords(string $str, int $maxWords, string $suffix = '...'): string
{
    $words = explode(' ', trim($str));
    if (count($words) <= $maxWords) {
        return $str;
    }
    return implode(' ', array_slice($words, 0, $maxWords)) . $suffix;
}

echo truncateWords('The quick brown fox jumps over the lazy dog', 4);
// The quick brown fox...

// 安全截断 HTML(不截断标签)
function truncateHtml(string $html, int $maxLength): string
{
    preg_match_all('/<[^>]+>|[^<]+/', $html, $tokens);
    $result = '';
    $openTags = [];

    foreach ($tokens[0] as $token) {
        if (preg_match('/^<(\w+)/', $token, $tagMatch)) {
            $result .= $token;
            if (!preg_match('/\/>$/', $token) && !preg_match('/<\/' . $tagMatch[1] . '/', $token)) {
                $openTags[] = $tagMatch[1];
            }
        } elseif (preg_match('/^<\/(\w+)/', $token, $tagMatch)) {
            $result .= $token;
            array_pop($openTags);
        } else {
            $remaining = $maxLength - mb_strlen($result, 'UTF-8');
            if ($remaining <= 0) break;
            $result .= mb_substr($token, 0, $remaining, 'UTF-8');
        }
        if (mb_strlen($result, 'UTF-8') >= $maxLength) break;
    }

    // 关闭未闭合的标签
    while (!empty($openTags)) {
        $result .= '</' . array_pop($openTags) . '>';
    }

    return $result;
}

PHP 8.1+ 新增

PHP 8.1 新增了 array_is_list() 用于检查数组是否为从 0 开始的连续索引数组。这在使用 json_encode 时很有用。

注意事项

编码问题

strlensubstrstrtolowerstrtoupper 等函数按字节操作,对非 ASCII 字符(如中文、日文)可能产生错误结果。处理多字节字符应使用 mb_* 系列函数。

strpos 返回值

strpos 找到匹配时返回位置索引(可能为 0),未找到时返回 false。必须使用 ===!== 进行比较,不能使用 ==!=

最佳实践

  1. 优先使用 PHP 8.0+ 新函数str_containsstr_starts_withstr_ends_with 更安全、更可读
  2. 多字节字符使用 mbstring:所有涉及中文的操作都应使用 mb_* 函数
  3. 字符串比较使用 ===:避免 strpos 返回值的 0 == false 陷阱
  4. 批量替换使用数组参数str_replace 支持数组参数,避免多次调用
  5. trim 去除用户输入两端空白:所有接收用户输入的场景都应先 trim()
  6. 使用 str_pad 格式化输出:数字补零、表格对齐等场景使用 str_pad()

参考链接