6.2 字符串操作函数

PHP提供了丰富的内置字符串函数,这些函数可以帮助我们高效地完成各种字符串处理任务。掌握这些函数是PHP开发的基本功,能大大提高开发效率。

字符串长度和计算函数

strlen() - 获取字符串长度

<?php
// 基本用法
$text = "Hello World";
$length = strlen($text);
echo "字符串长度: {$length}\n";  // 输出: 11

// 包含中文字符
$chinese = "你好世界";
echo "字节长度: " . strlen($chinese) . "\n";  // 输出: 12 (UTF-8编码)

// 空字符串
$empty = "";
echo "空字符串长度: " . strlen($empty) . "\n";  // 输出: 0
?>

mb_strlen() - 获取多字节字符串长度

<?php
// 设置内部编码
mb_internal_encoding('UTF-8');

$text = "Hello 你好世界!";
echo "字节长度: " . strlen($text) . "\n";        // 输出: 字节数
echo "字符数量: " . mb_strlen($text, 'UTF-8') . "\n";  // 输出: 字符数

// 指定不同编码
$gbk_text = "你好"; // 假设这是GBK编码
echo "GBK字符数: " . mb_strlen($gbk_text, 'GBK') . "\n";
?>

str_word_count() - 统计单词数量

<?php
$text = "Hello world! This is a PHP tutorial.";

// 返回单词数量
$word_count = str_word_count($text);
echo "单词数量: {$word_count}\n";  // 输出: 6

// 返回包含所有单词的数组
$words = str_word_count($text, 1);
print_r($words);

// 返回包含单词位置信息的数组
$words_with_positions = str_word_count($text, 2);
print_r($words_with_positions);

// 处理包含中文的文本
$chinese_text = "你好世界,PHP编程";
echo "英文单词数: " . str_word_count($chinese_text) . "\n";  // 可能无法正确统计中文
?>

str_count_chars() - 统计字符出现次数

<?php
$text = "Hello World! Hello PHP!";

// 返回所有字符出现次数的数组
$char_counts = str_count_chars($text, 0);
print_r($char_counts);

// 只返回出现过的字符
$used_chars = str_count_chars($text, 1);
print_r($used_chars);

// 模式2:返回包含字符ASCII值的数组,未出现的字符值为0
$all_chars = str_count_chars($text, 2);
print_r($all_chars);

// 实用函数:找出字符串中唯一的字符
function getUniqueChars($str) {
    return array_keys(str_count_chars($str, 1));
}

$unique_chars = getUniqueChars($text);
echo "唯一字符: " . implode(', ', $unique_chars) . "\n";
?>

字符串查找和定位函数

strpos() - 查找子字符串首次出现位置

<?php
$text = "Hello World, Hello PHP!";

// 查找子字符串
$position = strpos($text, "World");
echo "'World'位置: {$position}\n";  // 输出: 6

// 查找不存在的字符串
$not_found = strpos($text, "Python");
var_dump($not_found);  // 输出: false

// 使用严格比较
if (strpos($text, "Hello") !== false) {
    echo "找到了'Hello'\n";
}

// 从指定位置开始搜索
$second_hello = strpos($text, "Hello", 1);  // 从第2个字符开始
echo "第二个'Hello'位置: {$second_hello}\n";  // 输出: 13
?>

strrpos() - 查找子字符串最后出现位置

<?php
$text = "Hello World, Hello PHP! Hello Again!";

// 查找最后一次出现的位置
$last_hello = strrpos($text, "Hello");
echo "最后一个'Hello'位置: {$last_hello}\n";

// 实用示例:获取文件扩展名
function getFileExtension($filename) {
    $last_dot = strrpos($filename, '.');
    if ($last_dot === false) {
        return '';
    }
    return substr($filename, $last_dot + 1);
}

echo "文件扩展名: " . getFileExtension("document.pdf") . "\n";
echo "文件扩展名: " . getFileExtension("archive.tar.gz") . "\n";
echo "文件扩展名: " . getFileExtension("filename") . "\n";
?>

stripos() 和 strripos() - 大小写不敏感的查找

<?php
$text = "Hello World, hello PHP!";

// 大小写不敏感查找
$pos1 = stripos($text, "hello");  // 找到第一个
$pos2 = strripos($text, "hello"); // 找到最后一个

echo "第一个'hello'(不区分大小写): {$pos1}\n";
echo "最后一个'hello'(不区分大小写): {$pos2}\n";

// 实际应用:检查文本中是否包含关键词(不区分大小写)
function containsKeyword($text, $keyword) {
    return stripos($text, $keyword) !== false;
}

$article = "PHP是一种流行的编程语言...";
if (containsKeyword($article, "php")) {
    echo "文章包含PHP相关内容\n";
}
?>

strstr() 和 stristr() - 查找并返回子字符串

<?php
$email = "user@example.com";

// strstr - 大小写敏感
$domain = strstr($email, "@");
echo "域名部分: {$domain}\n";  // 输出: @example.com

// 只返回@之前的部分
$username = strstr($email, "@", true);
echo "用户名: {$username}\n";  // 输出: user

// stristr - 大小写不敏感
$text = "Hello World";
$result = stristr($text, "o");
echo "从'o'开始: {$result}\n";  // 输出: o World
?>

substr_count() - 统计子字符串出现次数

<?php
$text = "Hello Hello Hello World";

// 统计出现次数
$count = substr_count($text, "Hello");
echo "'Hello'出现次数: {$count}\n";  // 输出: 3

// 在指定范围内统计
$count_partial = substr_count($text, "Hello", 0, 10);
echo "前10个字符中'Hello'出现次数: {$count_partial}\n";  // 输出: 1

// 实际应用:检查密码强度
function checkPasswordStrength($password) {
    $issues = [];

    if (strlen($password) < 8) {
        $issues[] = "密码长度至少8位";
    }

    if (substr_count($password, $password[0]) > strlen($password) / 2) {
        $issues[] = "密码不应包含过多重复字符";
    }

    if (!preg_match('/[A-Z]/', $password)) {
        $issues[] = "密码应包含大写字母";
    }

    if (!preg_match('/[0-9]/', $password)) {
        $issues[] = "密码应包含数字";
    }

    return empty($issues) ? "密码强度良好" : implode(", ", $issues);
}

echo checkPasswordStrength("password123") . "\n";
echo checkPasswordStrength("aaaaaaaa") . "\n";
echo checkPasswordStrength("StrongPass123") . "\n";
?>

字符串截取和提取函数

substr() - 截取子字符串

<?php
$text = "Hello World!";

// 基本截取
$substring = substr($text, 6);
echo "从位置6开始: {$substring}\n";  // 输出: World!

// 指定长度
$substring2 = substr($text, 0, 5);
echo "前5个字符: {$substring2}\n";  // 输出: Hello

// 负数偏移量(从末尾开始)
$substring3 = substr($text, -6);
echo "最后6个字符: {$substring3}\n";  // 输出: World!

// 负数长度
$substring4 = substr($text, 0, -1);
echo "除最后一个字符: {$substring4}\n";  // 输出: Hello World

// 实用函数:生成字符串摘要
function getSummary($text, $length = 100, $suffix = '...') {
    if (mb_strlen($text, 'UTF-8') <= $length) {
        return $text;
    }
    return mb_substr($text, 0, $length, 'UTF-8') . $suffix;
}

$long_text = "这是一个很长的文本,需要截取生成摘要。在实际应用中,我们经常需要显示文章的摘要而不是完整内容。";
echo "摘要: " . getSummary($long_text, 30) . "\n";
?>

mb_substr() - 多字节安全的截取

<?php
// 中文字符串截取
$chinese = "你好,世界!欢迎学习PHP编程!";

// 错误的做法(使用substr)
$wrong = substr($chinese, 0, 10);  // 可能截断中文字符
echo "错误截取: {$wrong}\n";

// 正确的做法(使用mb_substr)
$correct = mb_substr($chinese, 0, 10, 'UTF-8');
echo "正确截取: {$correct}\n";

// 实用类:文本截取工具
class TextTruncator {
    private $encoding;

    public function __construct($encoding = 'UTF-8') {
        $this->encoding = $encoding;
    }

    /**
     * 截取指定长度的文本
     */
    public function truncate($text, $length, $suffix = '...') {
        if (mb_strlen($text, $this->encoding) <= $length) {
            return $text;
        }
        return mb_substr($text, 0, $length, $this->encoding) . $suffix;
    }

    /**
     * 截取单词边界的文本
     */
    public function truncateByWords($text, $wordCount, $suffix = '...') {
        $words = preg_split('/\s+/', $text);
        if (count($words) <= $wordCount) {
            return $text;
        }
        return implode(' ', array_slice($words, 0, $wordCount)) . $suffix;
    }
}

$truncator = new TextTruncator();
echo "按字符截取: " . $truncator->truncate($chinese, 15) . "\n";

$english = "This is a sample text for demonstration purposes.";
echo "按单词截取: " . $truncator->truncateByWords($english, 5) . "\n";
?>

substr_replace() - 替换子字符串

<?php
$text = "Hello World!";

// 替换指定范围的字符
$replaced = substr_replace($text, "PHP", 6, 5);
echo "替换后: {$replaced}\n";  // 输出: Hello PHP!

// 在指定位置插入
$inserted = substr_replace($text, " Beautiful", 5, 0);
echo "插入后: {$inserted}\n";  // 输出: Hello Beautiful World!

// 删除指定范围的字符
$deleted = substr_replace($text, "", 6, 6);
echo "删除后: {$deleted}\n";  // 输出: Hello !

// 实用函数:隐藏部分信息
function maskSensitiveInfo($data, $type = 'email') {
    switch ($type) {
        case 'email':
            $at = strpos($data, '@');
            if ($at !== false) {
                $username = substr($data, 0, $at);
                $domain = substr($data, $at);

                if (strlen($username) > 2) {
                    $masked_username = substr($username, 0, 2) . str_repeat('*', strlen($username) - 2);
                } else {
                    $masked_username = str_repeat('*', strlen($username));
                }

                return $masked_username . $domain;
            }
            break;

        case 'phone':
            if (strlen($data) > 4) {
                return substr($data, 0, 3) . str_repeat('*', strlen($data) - 6) . substr($data, -3);
            }
            break;

        case 'id_card':
            if (strlen($data) > 6) {
                return substr($data, 0, 6) . str_repeat('*', strlen($data) - 10) . substr($data, -4);
            }
            break;
    }

    return $data;
}

echo "邮箱隐藏: " . maskSensitiveInfo("zhangsan@example.com", "email") . "\n";
echo "手机号隐藏: " . maskSensitiveInfo("13812345678", "phone") . "\n";
echo "身份证隐藏: " . maskSensitiveInfo("110101199001011234", "id_card") . "\n";
?>

字符串替换函数

str_replace() - 替换所有匹配的字符串

<?php
$text = "Hello World! Hello PHP! Hello World!";

// 基本替换
$replaced = str_replace("Hello", "Hi", $text);
echo "替换后: {$replaced}\n";

// 多对多替换
$search = ["Hello", "World", "PHP"];
$replace = ["Hi", "Universe", "JavaScript"];
$multi_replaced = str_replace($search, $replace, $text);
echo "多对多替换: {$multi_replaced}\n";

// 统计替换次数
$replaced_count = str_replace("Hello", "Hi", $text, $count);
echo "替换次数: {$count}\n";

// 实用函数:处理用户输入,过滤敏感词
function filterSensitiveWords($text) {
    $sensitive_words = ['笨蛋', '白痴', '傻瓜', 'evil', 'stupid'];
    $replacements = array_fill(0, count($sensitive_words), '***');
    return str_replace($sensitive_words, $replacements, $text);
}

$user_input = "你这个笨蛋,真是个stupid!";
echo "过滤后: " . filterSensitiveWords($user_input) . "\n";
?>

str_ireplace() - 大小写不敏感的替换

<?php
$text = "Hello world! HELLO WORLD! hello world!";

// 大小写不敏感替换
$replaced = str_ireplace("hello", "hi", $text);
echo "不敏感替换: {$replaced}\n";

// 实际应用:URL友好化
function urlFriendly($string) {
    // 转换为小写
    $string = strtolower($string);

    // 替换空格和特殊字符
    $replacements = [
        ' ' => '-',
        '&' => 'and',
        '+' => 'plus'
    ];

    $string = str_ireplace(array_keys($replacements), array_values($replacements), $string);

    // 移除非字母数字字符(除了连字符)
    $string = preg_replace('/[^a-z0-9\-]/', '', $string);

    // 移除多余的连字符
    $string = preg_replace('/-+/', '-', $string);

    return trim($string, '-');
}

$url1 = "Hello World! This is a Test";
$url2 = "PHP & MySQL + Apache = LAMP";
echo "URL1: " . urlFriendly($url1) . "\n";
echo "URL2: " . urlFriendly($url2) . "\n";
?>

preg_replace() - 正则表达式替换

<?php
$text = "我的手机号是13812345678,邮箱是user@example.com,网站是https://www.example.com";

// 匹配手机号并隐藏
$hidden_phone = preg_replace('/(1[3-9]\d)\d{4}(\d{4})/', '$1****$2', $text);
echo "隐藏手机号: {$hidden_phone}\n";

// 匹配邮箱并部分隐藏
$hidden_email = preg_replace('/([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/', '$1***@$2', $text);
echo "隐藏邮箱: {$hidden_email}\n";

// 移除HTML标签
$html = "<div><p>这是一个<strong>重要</strong>的<strong>消息</strong>!</p></div>";
$plain_text = preg_replace('/<[^>]*>/', '', $html);
echo "纯文本: {$plain_text}\n";

// 实用函数:清理文本中的多余空白
function cleanWhitespace($text) {
    // 移除多余的空格
    $text = preg_replace('/\s+/', ' ', $text);

    // 移除首尾空格
    $text = trim($text);

    return $text;
}

$messy_text = "   这是一个     包含
    多个    空格和   换行符的    文本。   ";
echo "清理后: '" . cleanWhitespace($messy_text) . "'\n";
?>

字符串分割和连接函数

explode() - 分割字符串为数组

<?php
// 基本分割
$text = "apple,banana,orange,grape";
$fruits = explode(",", $text);
print_r($fruits);

// 限制分割数量
$text2 = "one,two,three,four,five";
$parts = explode(",", $text2, 3);
print_r($parts);

// 解析CSV格式
$csv_line = '"张三",25,"男","zhangsan@example.com"';
$csv_data = str_getcsv($csv_line);
print_r($csv_data);

// 实用函数:解析配置文件行
function parseConfigLine($line) {
    // 移除注释和空白
    $line = trim(preg_replace('/#.*$/', '', $line));

    if (empty($line) || strpos($line, '=') === false) {
        return null;
    }

    list($key, $value) = explode('=', $line, 2);
    return [
        'key' => trim($key),
        'value' => trim($value, ' "')
    ];
}

$config_line = 'database_host = "localhost"';
$parsed = parseConfigLine($config_line);
print_r($parsed);
?>

implode() 和 join() - 连接数组元素为字符串

<?php
$fruits = ["apple", "banana", "orange", "grape"];

// 连接数组元素
$string1 = implode(", ", $fruits);
$string2 = join(" | ", $fruits);  // join是implode的别名

echo "逗号连接: {$string1}\n";
echo "竖线连接: {$string2}\n";

// 实际应用:生成SQL IN子句
function generateInClause($array) {
    if (empty($array)) {
        return "";
    }

    // 转义每个值
    $escaped = array_map(function($value) {
        return "'" . addslashes($value) . "'";
    }, $array);

    return "IN (" . implode(", ", $escaped) . ")";
}

$usernames = ["张三", "李四", "王五"];
$sql = "SELECT * FROM users WHERE username " . generateInClause($usernames);
echo "SQL: {$sql}\n";

// 构建CSS类字符串
function buildClasses($classes) {
    // 过滤空值并去重
    $clean_classes = array_filter(array_unique($classes));
    return implode(" ", $clean_classes);
}

$element_classes = ["btn", "btn-primary", "", "btn-primary", "active"];
$class_string = buildClasses($element_classes);
echo "CSS类: '{$class_string}'\n";
?>

str_split() - 将字符串分割为字符数组

<?php
$text = "Hello";

// 分割为单个字符
$chars = str_split($text);
print_r($chars);

// 指定每组长度
$chunks = str_split($text, 2);
print_r($chunks);

// 实用函数:格式化电话号码
function formatPhoneNumber($phone) {
    // 移除所有非数字字符
    $digits = preg_replace('/\D/', '', $phone);

    if (strlen($digits) === 11) {
        $area = substr($digits, 0, 3);
        $prefix = substr($digits, 3, 4);
        $line = substr($digits, 7, 4);
        return "{$area}-{$prefix}-{$line}";
    }

    return $phone;
}

echo "格式化手机号: " . formatPhoneNumber("13812345678") . "\n";
echo "格式化电话号: " . formatPhoneNumber("(010) 1234-5678") . "\n";
?>

chunk_split() - 分割字符串为小块

<?php
$text = "HelloWorldHelloWorld";

// 每4个字符分割一次
$chunked = chunk_split($text, 4, "-");
echo "分割后: {$chunked}\n";

// 实际应用:格式化二进制数据
function formatBinaryData($data, $chunk_size = 8, $line_size = 8) {
    $binary = '';
    $chunks = str_split($data, $chunk_size);

    foreach ($chunks as $i => $chunk) {
        $binary .= bin2hex($chunk) . ' ';

        if (($i + 1) % $line_size === 0) {
            $binary .= "\n";
        }
    }

    return trim($binary);
}

$sample_data = "Hello World!";
echo "二进制格式:\n" . formatBinaryData($sample_data) . "\n";
?>

大小写转换函数

strtolower() - 转换为小写

<?php
$text = "Hello World! 你好世界!";

$lower = strtolower($text);
echo "小写: {$lower}\n";

// 实际应用:统一处理用户输入
function normalizeInput($input) {
    // 转换为小写并去除空白
    return strtolower(trim($input));
}

$user_input1 = "  ADMIN  ";
$user_input2 = "Admin";
$user_input3 = "ADMIN";

if (normalizeInput($user_input1) === normalizeInput($user_input2)) {
    echo "用户输入相同\n";
}
?>

strtoupper() - 转换为大写

<?php
$text = "Hello World! 你好世界!";

$upper = strtoupper($text);
echo "大写: {$upper}\n";

// 实用函数:生成验证码
function generateCaptcha($length = 6) {
    $chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
    $captcha = '';

    for ($i = 0; $i < $length; $i++) {
        $captcha .= $chars[rand(0, strlen($chars) - 1)];
    }

    return $captcha;
}

echo "验证码: " . generateCaptcha() . "\n";
?>

ucfirst() - 首字母大写

<?php
$text = "hello world";

$capitalized = ucfirst($text);
echo "首字母大写: {$capitalized}\n";

// 实用函数:格式化姓名
function formatName($name) {
    // 分割姓名并转换每个部分的首字母
    $parts = explode(' ', strtolower(trim($name)));
    $formatted_parts = array_map('ucfirst', $parts);
    return implode(' ', $formatted_parts);
}

echo "格式化姓名: " . formatName("john doe") . "\n";
echo "格式化姓名: " . formatName("MARY JANE") . "\n";
?>

ucwords() - 每个单词首字母大写

<?php
$text = "hello world! this is php.";

$capitalized = ucwords($text);
echo "每个单词首字母大写: {$capitalized}\n";

// 处理自定义分隔符
$text2 = "hello_world-php_javascript";
$capitalized2 = ucwords($text2, "_-");
echo "自定义分隔符: {$capitalized2}\n";

// 实用函数:格式化标题
function formatTitle($title) {
    // 转换为小写,然后每个单词首字母大写
    $title = strtolower($title);
    $title = ucwords($title);

    // 处理一些特殊情况
    $exceptions = ['a', 'an', 'the', 'and', 'but', 'or', 'for', 'nor', 'on', 'at', 'to', 'from', 'by'];
    $words = explode(' ', $title);

    foreach ($words as $i => &$word) {
        if ($i > 0 && in_array(strtolower($word), $exceptions)) {
            $word = strtolower($word);
        }
    }

    return implode(' ', $words);
}

echo "格式化标题: " . formatTitle("THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG") . "\n";
?>

字符串清理和修剪函数

trim() - 去除首尾空白

<?php
$text = "   Hello World!   \n\t";

$trimmed = trim($text);
echo "去除空白: '{$trimmed}'\n";

// 指定要去除的字符
$text2 = "...Hello World!!!";
$trimmed2 = trim($text2, ".!");
echo "去除指定字符: '{$trimmed2}'\n";

// 实用函数:清理用户输入
function cleanUserInput($input) {
    // 去除首尾空白
    $input = trim($input);

    // 移除多余的空格
    $input = preg_replace('/\s+/', ' ', $input);

    return $input;
}

$messy_input = "   张三    <script>alert('xss')</script>   ";
echo "清理后: '" . cleanUserInput($messy_input) . "'\n";
?>

ltrim() 和 rtrim() - 去除左侧或右侧空白

<?php
$text = "   Hello World!   ";

$left_trimmed = ltrim($text);
echo "去除左侧空白: '{$left_trimmed}'\n";

$right_trimmed = rtrim($text);
echo "去除右侧空白: '{$right_trimmed}'\n";

// 实际应用:清理文件路径
function cleanFilePath($path) {
    // 去除尾部斜杠
    $path = rtrim($path, '/\\');
    return $path;
}

$path1 = "/var/www/html/";
$path2 = "C:\\Users\\Documents\\";
echo "清理路径1: " . cleanFilePath($path1) . "\n";
echo "清理路径2: " . cleanFilePath($path2) . "\n";
?>

HTML和安全相关函数

htmlspecialchars() - HTML特殊字符转义

<?php
$user_input = '<script>alert("XSS Attack!");</script>';

// 转义HTML特殊字符
$safe_input = htmlspecialchars($user_input, ENT_QUOTES, 'UTF-8');
echo "安全输出: {$safe_input}\n";

// 实用函数:安全地输出用户内容
function safeEcho($content) {
    echo htmlspecialchars($content, ENT_QUOTES, 'UTF-8');
}

$comment = "<b>你好</b><script>alert('xss')</script>";
echo "安全输出: ";
safeEcho($comment);
echo "\n";
?>

htmlentities() - 转换所有HTML实体

<?php
$text = "中文 & English © 2024";

// 转换所有HTML实体
$encoded = htmlentities($text, ENT_QUOTES, 'UTF-8');
echo "HTML实体: {$encoded}\n";

// 实用函数:准备邮件内容
function prepareEmailContent($content) {
    // 转换HTML实体
    $content = htmlentities($content, ENT_QUOTES, 'UTF-8');

    // 转换换行符
    $content = nl2br($content);

    return $content;
}

$email_content = "你好\n这是一封测试邮件\n包含特殊字符: < > & \" '";
echo "邮件内容: " . prepareEmailContent($email_content) . "\n";
?>

strip_tags() - 移除HTML和PHP标签

<?php
$html = "<div><p>这是一段<strong>重要</strong>的文字。</p><script>alert('xss')</script></div>";

// 移除所有标签
$plain_text = strip_tags($html);
echo "纯文本: {$plain_text}\n";

// 保留指定标签
$allowed_html = strip_tags($html, '<strong><em>');
echo "允许的标签: {$allowed_html}\n";

// 实用函数:清理用户输入的HTML
function sanitizeHTML($html, $allowed_tags = '<p><br><strong><em><ul><ol><li>') {
    // 移除危险属性
    $html = preg_replace('/\s*on\w+="[^"]*"/i', '', $html);

    // 保留允许的标签
    $clean_html = strip_tags($html, $allowed_tags);

    return $clean_html;
}

$user_html = '<p onclick="alert(\'xss\')">点击这里</p><strong>重要内容</strong>';
echo "清理后的HTML: " . sanitizeHTML($user_html) . "\n";
?>

addslashes() 和 stripslashes() - 转义和反转义引号

<?php
$text = "Don't forget to escape \"quotes\"";

// 转义引号
$escaped = addslashes($text);
echo "转义后: {$escaped}\n";

// 反转义
$unescaped = stripslashes($escaped);
echo "反转义后: {$unescaped}\n";

// 实际应用:准备数据库查询(现在更推荐使用预处理语句)
function escapeForDatabase($value) {
    return "'" . addslashes($value) . "'";
}

$name = "O'Reilly";
$safe_name = escapeForDatabase($name);
echo "数据库安全: {$safe_name}\n";
?>

综合应用示例

文本处理工具类

<?php
class TextProcessor {
    /**
     * 清理和标准化文本
     */
    public static function clean($text) {
        // 去除HTML标签
        $text = strip_tags($text);

        // 转换HTML实体
        $text = html_entity_decode($text, ENT_QUOTES, 'UTF-8');

        // 标准化空白字符
        $text = preg_replace('/\s+/', ' ', $text);

        // 去除首尾空白
        $text = trim($text);

        return $text;
    }

    /**
     * 生成URL友好的slug
     */
    public static function slug($text, $length = 50) {
        // 转换为小写
        $text = strtolower($text);

        // 替换非字母数字字符为连字符
        $text = preg_replace('/[^a-z0-9]+/', '-', $text);

        // 移除开头和结尾的连字符
        $text = trim($text, '-');

        // 限制长度
        if (strlen($text) > $length) {
            $text = substr($text, 0, $length);
            $text = trim($text, '-');
        }

        return $text ?: 'untitled';
    }

    /**
     * 截取文本并保留单词完整性
     */
    public static function excerpt($text, $length = 150, $suffix = '...') {
        $text = self::clean($text);

        if (mb_strlen($text, 'UTF-8') <= $length) {
            return $text;
        }

        // 截取到指定长度
        $excerpt = mb_substr($text, 0, $length, 'UTF-8');

        // 找到最后一个空格,避免截断单词
        $last_space = mb_strrpos($excerpt, ' ', 'UTF-8');
        if ($last_space !== false) {
            $excerpt = mb_substr($excerpt, 0, $last_space, 'UTF-8');
        }

        return $excerpt . $suffix;
    }

    /**
     * 高亮关键词
     */
    public static function highlightKeywords($text, $keywords) {
        if (empty($keywords)) {
            return $text;
        }

        if (!is_array($keywords)) {
            $keywords = [$keywords];
        }

        foreach ($keywords as $keyword) {
            if (!empty(trim($keyword))) {
                $pattern = '/(' . preg_quote($keyword, '/') . ')/i';
                $replacement = '<mark>$1</mark>';
                $text = preg_replace($pattern, $replacement, $text);
            }
        }

        return $text;
    }

    /**
     * 计算文本统计信息
     */
    public static function statistics($text) {
        $text = self::clean($text);

        return [
            'characters' => mb_strlen($text, 'UTF-8'),
            'characters_no_spaces' => mb_strlen(preg_replace('/\s/', '', $text), 'UTF-8'),
            'words' => str_word_count($text),
            'sentences' => preg_match_all('/[.!?]+/', $text, $matches),
            'paragraphs' => count(preg_split('/\n\s*\n/', $text)),
            'reading_time' => ceil(str_word_count($text) / 200)  // 假设每分钟200字
        ];
    }
}

// 使用示例
$article = "PHP是一种广泛使用的开源脚本语言,特别适合Web开发。它可以嵌入HTML中,或者作为命令行脚本运行。PHP支持多种数据库,易于学习,拥有庞大的开发者社区。";

echo "清理后: " . TextProcessor::clean($article) . "\n";
echo "Slug: " . TextProcessor::slug($article) . "\n";
echo "摘要: " . TextProcessor::excerpt($article, 50) . "\n";

$highlighted = TextProcessor::highlightKeywords($article, ['PHP', 'Web']);
echo "高亮关键词: {$highlighted}\n";

$stats = TextProcessor::statistics($article);
echo "统计信息:\n";
foreach ($stats as $key => $value) {
    echo "  {$key}: {$value}\n";
}
?>

用户输入验证和处理

<?php
class InputValidator {
    /**
     * 验证用户名
     */
    public static function validateUsername($username) {
        $errors = [];

        // 清理输入
        $username = trim($username);

        // 检查长度
        $length = mb_strlen($username, 'UTF-8');
        if ($length < 3) {
            $errors[] = "用户名至少需要3个字符";
        } elseif ($length > 20) {
            $errors[] = "用户名不能超过20个字符";
        }

        // 检查字符格式
        if (!preg_match('/^[a-zA-Z0-9_\x{4e00}-\x{9fa5}]+$/u', $username)) {
            $errors[] = "用户名只能包含字母、数字、下划线和中文字符";
        }

        // 检查是否以下划线或数字开头
        if (preg_match('/^[0-9_]/', $username)) {
            $errors[] = "用户名不能以下划线或数字开头";
        }

        return empty($errors) ? true : $errors;
    }

    /**
     * 验证邮箱地址
     */
    public static function validateEmail($email) {
        $errors = [];

        // 清理输入
        $email = strtolower(trim($email));

        // 基本格式验证
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            $errors[] = "邮箱格式不正确";
            return $errors;
        }

        // 长度检查
        if (strlen($email) > 254) {
            $errors[] = "邮箱地址过长";
        }

        // 检查是否包含中文字符
        if (preg_match('/[\x{4e00}-\x{9fa5}]/u', $email)) {
            $errors[] = "邮箱地址不能包含中文字符";
        }

        return empty($errors) ? true : $errors;
    }

    /**
     * 验证手机号(中国大陆)
     */
    public static function validatePhone($phone) {
        $errors = [];

        // 清理输入
        $phone = preg_replace('/\D/', '', $phone);  // 只保留数字

        // 检查长度
        if (strlen($phone) !== 11) {
            $errors[] = "手机号必须是11位数字";
            return $errors;
        }

        // 检查格式
        if (!preg_match('/^1[3-9]\d{9}$/', $phone)) {
            $errors[] = "手机号格式不正确";
        }

        return empty($errors) ? true : $errors;
    }

    /**
     * 清理用户输入内容
     */
    public static function sanitizeContent($content) {
        // 去除HTML标签
        $content = strip_tags($content);

        // 转义特殊字符
        $content = htmlspecialchars($content, ENT_QUOTES, 'UTF-8');

        // 标准化空白字符
        $content = preg_replace('/\s+/', ' ', $content);

        // 去除首尾空白
        $content = trim($content);

        return $content;
    }
}

// 测试验证函数
$test_cases = [
    'username' => ['张三123', 'a', '123张三', 'user@name'],
    'email' => ['user@example.com', 'invalid.email', '用户@邮箱.com', 'a' . str_repeat('a', 250) . '@example.com'],
    'phone' => ['13812345678', '12345678901', '188-1234-5678', '1381234567']
];

echo "用户名验证结果:\n";
foreach ($test_cases['username'] as $username) {
    $result = InputValidator::validateUsername($username);
    echo "  {$username}: " . (is_array($result) ? implode(', ', $result) : '通过') . "\n";
}

echo "\n邮箱验证结果:\n";
foreach ($test_cases['email'] as $email) {
    $result = InputValidator::validateEmail($email);
    echo "  {$email}: " . (is_array($result) ? implode(', ', $result) : '通过') . "\n";
}

echo "\n手机号验证结果:\n";
foreach ($test_cases['phone'] as $phone) {
    $result = InputValidator::validatePhone($phone);
    echo "  {$phone}: " . (is_array($result) ? implode(', ', $result) : '通过') . "\n";
}
?>

本节练习

基础练习

  1. 使用strlen()mb_strlen()分别统计中英文字符串的长度
  2. 使用str_replace()替换文本中的敏感词
  3. 使用explode()implode()处理CSV格式数据
  4. 使用substr()截取字符串生成摘要

进阶练习

  1. 创建一个函数,统计字符串中每个单词出现的频率
  2. 实现一个URL slug生成器,处理中英文混合输入
  3. 编写一个密码强度检查器,检查长度、复杂度等
  4. 创建一个文本高亮函数,高亮显示搜索关键词

实战练习

  1. 完善TextProcessor类,添加更多实用方法
  2. 扩展InputValidator类,支持更多验证规则
  3. 创建一个简单的模板引擎,支持变量替换和条件渲染
  4. 实现一个文章管理系统的文本处理功能

总结

本节我们学习了PHP中常用的字符串处理函数,包括:

  • 长度计算函数strlen(), mb_strlen(), str_word_count()
  • 查找定位函数strpos(), strrpos(), strstr(), substr_count()
  • 截取提取函数substr(), mb_substr(), substr_replace()
  • 替换函数str_replace(), preg_replace(), substr_replace()
  • 分割连接函数explode(), implode(), str_split()
  • 大小写转换strtolower(), strtoupper(), ucfirst(), ucwords()
  • 清理修剪函数trim(), ltrim(), rtrim()
  • 安全函数htmlspecialchars(), strip_tags(), addslashes()

掌握这些函数是PHP开发的基础技能。在实际开发中,要根据具体需求选择合适的函数,特别注意中文处理时的编码问题,以及用户输入的安全处理。

💡 学习建议

  1. 熟记常用函数的参数和返回值
  2. 注意区分普通字符串函数和多字节字符串函数
  3. 处理用户输入时要始终考虑安全性
  4. 多查看PHP官方文档了解更多函数细节

下一节预告:我们将学习正则表达式,这是文本处理的强大工具,能够处理更复杂的模式匹配和替换任务。