字符串处理

学习PHP字符串操作、函数和正则表达式

PHP字符串概述

字符串是字符的序列,在PHP中是最常用的数据类型之一。PHP提供了丰富的字符串处理函数。

字符串定义方式:
  • 单引号: 不解析变量和转义字符(除了\\和\')
  • 双引号: 解析变量和所有转义字符
  • Heredoc: 类似双引号,用于多行字符串
  • Nowdoc: 类似单引号,用于多行字符串

字符串在PHP中的重要性

字符串处理是PHP编程中最常见的任务之一,几乎所有的Web应用都需要处理文本数据。PHP提供了超过100个内置字符串函数,涵盖了字符串操作的各个方面。

字符串编码

PHP默认使用ISO-8859-1编码,但在现代Web开发中,通常使用UTF-8编码。确保正确处理多字节字符对于国际化应用至关重要。

设置字符编码
<?php
// 设置PHP脚本的字符编码为UTF-8
header('Content-Type: text/html; charset=utf-8');
// 设置内部字符编码
mb_internal_encoding('UTF-8');
?>

字符串定义

PHP支持多种方式定义字符串。

字符串定义示例
<?php
// 单引号
$str1 = '这是一个单引号字符串';
echo $str1 . "<br>";

// 双引号(解析变量)
$name = "张三";
$str2 = "欢迎 $name 访问我们的网站";
echo $str2 . "<br>";

// Heredoc语法
$str3 = <<<EOD
这是一个多行字符串
使用Heredoc语法
可以包含变量:$name
EOD;
echo $str3 . "<br>";

// Nowdoc语法(不解析变量)
$str4 = <<<'EOD'
这是一个多行字符串
使用Nowdoc语法
不解析变量:$name
EOD;
echo $str4 . "<br>";

// 转义字符
$str5 = "这是第一行\n这是第二行\t这是制表符";
echo $str5 . "<br>";

// 在HTML中,使用<br>代替\n
$str6 = "这是第一行<br>这是第二行";
echo $str6;
?>

字符串连接

PHP使用点号(.)来连接字符串。在大型字符串拼接操作中,使用implode()函数通常比连续使用点号更高效。

字符串连接示例
<?php
// 使用点号连接
$firstName = "张";
$lastName = "三";
$fullName = $firstName . " " . $lastName;
echo $fullName . "<br>";

// 使用implode连接数组元素
$words = ["PHP", "是", "一种", "服务器端", "脚本语言"];
$sentence = implode(" ", $words);
echo $sentence . "<br>";

// 使用sprintf格式化字符串
$formatted = sprintf("欢迎 %s,您已经学习了 %d 天PHP", $fullName, 30);
echo $formatted;
?>

字符串长度和统计

获取字符串的长度和统计字符出现次数。

字符串长度和统计示例
<?php
$text = "Hello, World! 你好,世界!";

// strlen() - 获取字符串长度(字节数)
echo "字符串长度(字节): " . strlen($text) . "<br>";

// mb_strlen() - 获取字符串长度(字符数)
echo "字符串长度(字符): " . mb_strlen($text, 'UTF-8') . "<br>";

// str_word_count() - 统计单词数
$englishText = "Hello world, this is PHP";
echo "单词数: " . str_word_count($englishText) . "<br>";

// substr_count() - 统计子串出现次数
$text = "PHP is a popular scripting language. PHP is widely used.";
echo "PHP出现次数: " . substr_count($text, "PHP") . "<br>";

// count_chars() - 返回字符统计信息
$chars = count_chars($text, 1);
echo "字符统计: <br>";
foreach ($chars as $char => $count) {
    echo "字符 '" . chr($char) . "' 出现 $count 次<br>";
}
?>

字符串编码检测和转换

处理多语言内容时,正确检测和转换字符编码非常重要。

编码检测和转换示例
<?php
$text = "你好,世界!";

// 检测编码
$encoding = mb_detect_encoding($text);
echo "检测到的编码: $encoding<br>";

// 转换编码
$gbkText = mb_convert_encoding($text, "GBK", "UTF-8");
echo "转换为GBK: " . bin2hex($gbkText) . "<br>";

// 检查字符串是否包含特定编码的字符
if (mb_check_encoding($text, 'UTF-8')) {
    echo "字符串是有效的UTF-8编码<br>";
}

// 移除BOM头
$textWithBom = "\xEF\xBB\xBF" . "带BOM的文本";
$textWithoutBom = preg_replace('/^\xEF\xBB\xBF/', '', $textWithBom);
echo "移除BOM后的文本: $textWithoutBom<br>";
?>

字符串查找和替换

在字符串中查找内容并进行替换。

字符串查找和替换示例
<?php
$text = "Hello, World! Welcome to PHP programming.";

// strpos() - 查找字符串首次出现的位置
$position = strpos($text, "World");
echo "'World'首次出现在位置: $position<br>";

// stripos() - 不区分大小写的查找
$position = stripos($text, "world");
echo "'world'(不区分大小写)首次出现在位置: $position<br>";

// strrpos() - 查找字符串最后一次出现的位置
$position = strrpos($text, "o");
echo "'o'最后一次出现在位置: $position<br>";

// str_replace() - 字符串替换
$newText = str_replace("PHP", "JavaScript", $text);
echo "替换后: $newText<br>";

// str_ireplace() - 不区分大小写的替换
$newText = str_ireplace("php", "Python", $text);
echo "不区分大小写替换后: $newText<br>";

// substr_replace() - 替换字符串的子串
$newText = substr_replace($text, "Universe", 7, 5);
echo "子串替换后: $newText<br>";

// strtr() - 字符转换
$trans = ["Hello" => "Hi", "World" => "There"];
$newText = strtr($text, $trans);
echo "字符转换后: $newText<br>";
?>

高级查找和替换技巧

使用更复杂的模式进行字符串查找和替换。

高级查找替换示例
<?php
// 使用数组进行多重替换
$search = ["apple", "banana", "orange"];
$replace = ["苹果", "香蕉", "橙子"];
$text = "I like apple, banana and orange.";
$newText = str_replace($search, $replace, $text);
echo "多重替换: $newText<br>";

// 使用回调函数进行替换
$text = "The price is 100 dollars.";
$newText = preg_replace_callback(
    '/\d+/',
    function($matches) {
        return $matches[0] * 6.5 . " yuan";
    },
    $text
);
echo "回调替换: $newText<br>";

// 查找所有出现的位置
$text = "This is a test. Test is important.";
$positions = [];
$offset = 0;
while (($pos = stripos($text, "test", $offset)) !== false) {
    $positions[] = $pos;
    $offset = $pos + 1;
}
echo "'test'出现的位置: " . implode(", ", $positions) . "<br>";
?>

字符串截取和分割

从字符串中提取部分内容或将字符串分割成数组。

字符串截取和分割示例
<?php
$text = "Hello, World! Welcome to PHP programming.";

// substr() - 截取字符串
$part = substr($text, 7, 5);  // 从位置7开始,截取5个字符
echo "截取的部分: '$part'<br>";

// 从末尾开始截取
$part = substr($text, -11);  // 截取最后11个字符
echo "从末尾截取: '$part'<br>";

// explode() - 将字符串分割成数组
$words = explode(" ", $text);
echo "分割成单词: <br>";
print_r($words);
echo "<br>";

// implode() - 将数组元素连接成字符串
$newText = implode("-", $words);
echo "连接后的字符串: $newText<br>";

// str_split() - 将字符串分割为数组
$chars = str_split("Hello");
echo "分割成字符: <br>";
print_r($chars);
echo "<br>";

// chunk_split() - 将字符串分割成小块
$chunked = chunk_split("1234567890", 3, "-");
echo "分块后的字符串: $chunked<br>";
?>

多字节字符串处理

处理中文等多字节字符时,需要使用mbstring扩展函数。

多字节字符串处理示例
<?php
$chineseText = "欢迎学习PHP字符串处理";

// mb_substr() - 安全截取多字节字符串
$part = mb_substr($chineseText, 2, 4, 'UTF-8');
echo "截取的部分: '$part'<br>";

// mb_strcut() - 按字节数截取,但保证不截断字符
$part = mb_strcut($chineseText, 0, 10, 'UTF-8');
echo "按字节截取: '$part'<br>";

// 安全处理中文字符串长度
$length = mb_strlen($chineseText, 'UTF-8');
echo "中文字符串长度: $length<br>";

// 处理中英混合字符串
$mixedText = "Hello 你好 World 世界";
$mixedLength = mb_strlen($mixedText, 'UTF-8');
echo "混合字符串长度: $mixedLength<br>";
?>

字符串大小写转换

改变字符串中字母的大小写。

字符串大小写转换示例
<?php
$text = "hello, world! welcome to php programming.";

// strtoupper() - 转换为大写
echo "大写: " . strtoupper($text) . "<br>";

// strtolower() - 转换为小写
$text = "HELLO, WORLD! WELCOME TO PHP PROGRAMMING.";
echo "小写: " . strtolower($text) . "<br>";

// ucfirst() - 首字母大写
$text = "hello, world!";
echo "首字母大写: " . ucfirst($text) . "<br>";

// ucwords() - 每个单词首字母大写
echo "每个单词首字母大写: " . ucwords($text) . "<br>";

// lcfirst() - 首字母小写
$text = "Hello, World!";
echo "首字母小写: " . lcfirst($text) . "<br>";

// 混合使用
$name = "john doe";
$formattedName = ucwords($name);
echo "格式化姓名: $formattedName<br>";
?>

字符串修剪和填充

去除字符串两端的空格或特定字符,或在字符串两端添加字符。

字符串修剪和填充示例
<?php
$text = "   Hello, World!   ";

// trim() - 去除两端空格
echo "去除两端空格: '" . trim($text) . "'<br>";

// ltrim() - 去除左端空格
echo "去除左端空格: '" . ltrim($text) . "'<br>";

// rtrim() - 去除右端空格
echo "去除右端空格: '" . rtrim($text) . "'<br>";

// 去除特定字符
$text = "***Hello, World!***";
echo "去除星号: '" . trim($text, "*") . "'<br>";

// str_pad() - 填充字符串
$text = "Hello";
echo "右填充: '" . str_pad($text, 10, "-") . "'<br>";
echo "左填充: '" . str_pad($text, 10, "-", STR_PAD_LEFT) . "'<br>";
echo "两端填充: '" . str_pad($text, 10, "-", STR_PAD_BOTH) . "'<br>";

// str_repeat() - 重复字符串
echo "重复字符串: '" . str_repeat("*-", 5) . "'<br>";
?>

高级修剪和填充技巧

处理更复杂的修剪和填充需求。

高级修剪填充示例
<?php
// 去除HTML标签
$htmlText = "<p>这是一个<strong>段落</strong></p>";
$plainText = strip_tags($htmlText);
echo "去除HTML标签: '$plainText'<br>";

// 去除多余的空格
$textWithSpaces = "这    是    有    很多    空格的    文本";
$cleanText = preg_replace('/\s+/', ' ', $textWithSpaces);
echo "去除多余空格: '$cleanText'<br>";

// 使用wordwrap自动换行
$longText = "这是一个很长的文本,需要被自动换行显示在页面上。";
$wrappedText = wordwrap($longText, 10, "<br>\n");
echo "自动换行: <br>$wrappedText<br>";

// 格式化数字
$number = 1234567.89;
$formattedNumber = number_format($number, 2, '.', ',');
echo "格式化数字: $formattedNumber<br>";
?>

字符串比较和编码

比较字符串的内容和处理字符串编码。

字符串比较和编码示例
<?php
// strcmp() - 二进制安全字符串比较
$str1 = "Hello";
$str2 = "Hello";
$str3 = "hello";

echo "str1 vs str2: " . strcmp($str1, $str2) . "<br>";  // 0 (相等)
echo "str1 vs str3: " . strcmp($str1, $str3) . "<br>";  // -1 (小于)

// strcasecmp() - 不区分大小写的比较
echo "str1 vs str3 (不区分大小写): " . strcasecmp($str1, $str3) . "<br>";  // 0 (相等)

// strnatcmp() - 自然顺序比较
$files = ["file1.txt", "file10.txt", "file2.txt"];
usort($files, "strnatcmp");
echo "自然排序: " . implode(", ", $files) . "<br>";

// 编码转换
$text = "你好,世界!";
$gbkText = mb_convert_encoding($text, "GBK", "UTF-8");
echo "转换为GBK: " . bin2hex($gbkText) . "<br>";

// 检测编码
$encoding = mb_detect_encoding($text);
echo "检测到的编码: $encoding<br>";

// htmlspecialchars() - 转换HTML特殊字符
$html = "<script>alert('XSS')</script>";
echo "HTML转义: " . htmlspecialchars($html) . "<br>";

// htmlentities() - 转换所有HTML字符
echo "HTML实体: " . htmlentities($html) . "<br>";
?>

字符串安全处理

防止字符串处理中的安全漏洞。

字符串安全处理示例
<?php
// 防止SQL注入
$userInput = "'; DROP TABLE users; --";
$safeInput = addslashes($userInput);
echo "转义后的输入: $safeInput<br>";

// 更好的方式是使用预处理语句,但addslashes可用于简单场景

// 防止XSS攻击
$userContent = "<script>alert('恶意代码')</script><p>正常内容</p>";
$safeContent = htmlspecialchars($userContent, ENT_QUOTES, 'UTF-8');
echo "安全的HTML内容: $safeContent<br>";

// URL编码
$urlParam = "搜索关键词 & 特殊字符";
$encodedParam = urlencode($urlParam);
echo "URL编码: $encodedParam<br>";

// 基础64编码
$data = "需要编码的敏感数据";
$encodedData = base64_encode($data);
$decodedData = base64_decode($encodedData);
echo "Base64编码: $encodedData<br>";
echo "Base64解码: $decodedData<br>";
?>

正则表达式

使用正则表达式进行复杂的字符串匹配和替换。

正则表达式示例
<?php
$text = "我的电话号码是:138-1234-5678,邮箱是:example@email.com";

// preg_match() - 执行匹配
$pattern = '/\d{3}-\d{4}-\d{4}/';
if (preg_match($pattern, $text, $matches)) {
    echo "找到电话号码: " . $matches[0] . "<br>";
}

// preg_match_all() - 执行全局匹配
$pattern = '/\b\w+@\w+\.\w+\b/';
if (preg_match_all($pattern, $text, $matches)) {
    echo "找到邮箱: " . implode(", ", $matches[0]) . "<br>";
}

// preg_replace() - 执行替换
$pattern = '/\d{3}-\d{4}-\d{4}/';
$replacement = "***-****-****";
$newText = preg_replace($pattern, $replacement, $text);
echo "替换后: $newText<br>";

// preg_split() - 通过正则表达式分割字符串
$pattern = '/\s+/';  // 一个或多个空格
$words = preg_split($pattern, "Hello   World    PHP");
echo "正则分割: <br>";
print_r($words);
echo "<br>";

// 验证电子邮件格式
$email = "test@example.com";
$pattern = '/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/';
if (preg_match($pattern, $email)) {
    echo "$email 是有效的邮箱地址<br>";
} else {
    echo "$email 不是有效的邮箱地址<br>";
}
?>

常用正则表达式模式

收集一些常用的正则表达式模式,方便日常开发使用。

常用正则表达式模式
<?php
// 常用正则表达式模式示例
$patterns = [
    'email' => '/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/',
    'phone' => '/^1[3-9]\d{9}$/', // 中国手机号
    'id_card' => '/^\d{17}[\dXx]$/', // 身份证号
    'url' => '/^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/',
    'ip' => '/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/',
    'date' => '/^\d{4}-\d{2}-\d{2}$/', // YYYY-MM-DD
    'chinese' => '/^[\x{4e00}-\x{9fa5}]+$/u', // 中文字符
];

// 测试正则表达式
$testEmail = "test@example.com";
if (preg_match($patterns['email'], $testEmail)) {
    echo "$testEmail 是有效的邮箱地址<br>";
}

// 提取HTML标签内容
$html = '<div class="content"><p>第一段</p><p>第二段</p></div>';
preg_match_all('/<p>(.*?)<\/p>/', $html, $matches);
echo "提取的段落: <br>";
print_r($matches[1]);
echo "<br>";

// 使用命名捕获组
$date = "2023-10-25";
$pattern = '/(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})/';
preg_match($pattern, $date, $matches);
echo "年份: " . $matches['year'] . ", 月份: " . $matches['month'] . ", 日期: " . $matches['day'] . "<br>";
?>

字符串性能优化

了解字符串操作的性能特点,编写高效的字符串处理代码。

字符串拼接性能

不同字符串拼接方法的性能差异。

字符串拼接性能比较
<?php
// 测试不同拼接方法的性能
$start = microtime(true);

// 方法1:使用点号连续拼接(性能较差)
$result = "";
for ($i = 0; $i < 10000; $i++) {
    $result .= "字符串" . $i;
}
$time1 = microtime(true) - $start;

// 方法2:使用数组和implode(性能较好)
$start = microtime(true);
$parts = [];
for ($i = 0; $i < 10000; $i++) {
    $parts[] = "字符串" . $i;
}
$result = implode("", $parts);
$time2 = microtime(true) - $start;

echo "点号拼接时间: $time1 秒<br>";
echo "implode拼接时间: $time2 秒<br>";

// 方法3:使用sprintf(适合格式化字符串)
$formatted = sprintf("欢迎 %s,您已经学习了 %d 天PHP", "张三", 30);
echo "sprintf格式化: $formatted<br>";
?>

内存使用优化

减少字符串操作的内存占用。

内存使用优化示例
<?php
// 使用引用避免不必要的内存复制
function processLargeString(&$str) {
    // 直接操作原字符串,避免复制
    $str = strtoupper($str);
}

$largeString = "这是一个很大的字符串...";
processLargeString($largeString);
echo "处理后的字符串: $largeString<br>";

// 及时释放不再使用的大字符串
$bigData = str_repeat("x", 1000000); // 1MB的字符串
// 处理...
$bigData = null; // 及时释放内存
gc_collect_cycles(); // 强制垃圾回收

echo "内存已释放<br>";
?>

实践练习

创建一个PHP程序,实现以下功能:

  1. 使用不同方式定义字符串
  2. 实现字符串的查找、替换和截取操作
  3. 进行字符串大小写转换和修剪
  4. 使用正则表达式验证和提取数据
  5. 处理字符串编码和HTML转义
  6. 创建一个简单的文本处理工具
提示: 可以创建一个文本处理工具,实现大小写转换、空格修剪、字符统计、关键词替换等功能。
文本处理工具示例
<?php
// 简单的文本处理工具
function textProcessor($text, $operation) {
    switch ($operation) {
        case 'upper':
            return strtoupper($text);
        case 'lower':
            return strtolower($text);
        case 'title':
            return ucwords($text);
        case 'trim':
            return trim($text);
        case 'reverse':
            return strrev($text);
        case 'word_count':
            return str_word_count($text);
        default:
            return $text;
    }
}

// 测试文本处理工具
$testText = "  Hello, World! This is a test.  ";
echo "原始文本: '$testText'<br>";
echo "大写: '" . textProcessor($testText, 'upper') . "'<br>";
echo "修剪: '" . textProcessor($testText, 'trim') . "'<br>";
echo "单词数: " . textProcessor($testText, 'word_count') . "<br>";
?>