| 函式 | 用途 | 預設移除字元 | 支援自訂字元 | 多位元組安全 |
|---|---|---|---|---|
trim() | 移除首尾 | " \t\n\r\0\x0B" (空白、tab、換行、回車、null、垂直定位) | 是 (第 2 參數) | 否 (逐位元組) |
ltrim() | 移除左側 | 同上 | 是 | 否 |
rtrim() | 移除右側 | 同上 | 是 | 否 |
mb_trim() | 移除首尾 (Unicode 感知) | 所有 Unicode 空白字元 (Zs, Zl, Zp) | 是 | 是 (PHP 8.3+) |
mb_ltrim() | 移除左側 | 同上 | 是 | 是 (PHP 8.3+) |
mb_rtrim() | 移除右側 | 同上 | 是 | 是 (PHP 8.3+) |
<?php
$str = " \t\n Hello World \r\n ";
echo '[' . trim($str) . ']'; // [Hello World]
echo '[' . ltrim($str) . ']'; // [Hello World \r\n ]
echo '[' . rtrim($str) . ']'; // [ \t\n Hello World]
// 自訂移除字元
$csv = ',,apple,banana,,';
echo trim($csv, ','); // apple,banana
echo trim($csv, ', '); // apple,banana (空白+逗號)
// 移除特定字元組合
$paren = '(hello)';
echo trim($paren, '()'); // hello
echo trim($paren, '(,)'); // hello (移除 ( , ) 三種字元)
?>
標準 trim() 僅處理 ASCII 空白。全形空白 U+3000 ( )、零寬空白 U+200B、不換行空白 U+00A0 等不會被移除。
<?php
$str = " Hello World "; // 全形空白 U+3000
echo '[' . trim($str) . ']'; // [ Hello World ] ← 未移除!
// PHP 8.3+ 內建 mb_trim (最佳解)
if (function_exists('mb_trim')) {
echo '[' . mb_trim($str) . ']'; // [Hello World] ✓
}
// PHP 8.3 以下:相容性 polyfill
if (!function_exists('mb_trim')) {
function mb_trim(string $string, string $characters = ''): string {
if ($characters === '') {
// 移除所有 Unicode 空白字元 (General Category: Zs, Zl, Zp)
return preg_replace('/^[\p{Z}\p{C}]++|[\p{Z}\p{C}]++$/u', '', $string);
}
// 自訂字元:需逐字元處理
$chars = '[' . preg_quote($characters, '/') . ']';
return preg_replace('/^' . $chars . '++|' . $chars . '++$/u', '', $string);
}
function mb_ltrim(string $string, string $characters = ''): string {
if ($characters === '') return preg_replace('/^[\p{Z}\p{C}]++/u', '', $string);
$chars = '[' . preg_quote($characters, '/') . ']';
return preg_replace('/^' . $chars . '++/u', '', $string);
}
function mb_rtrim(string $string, string $characters = ''): string {
if ($characters === '') return preg_replace('/[\p{Z}\p{C}]++$/u', '', $string);
$chars = '[' . preg_quote($characters, '/') . ']';
return preg_replace('/' . $chars . '++$/u', '', $string);
}
}
// 測試各種 Unicode 空白
$tests = [
" \t\nHello\r\n ", // ASCII 空白
" Hello ", // 全形空白 U+3000
"\u{200B}Hello\u{200B}", // 零寬空白 U+200B
"\u{00A0}Hello\u{00A0}", // 不換行空白 U+00A0
"\u{202F}Hello\u{202F}", // 窄不換行空白 U+202F
];
foreach ($tests as $t) {
echo '原始: ' . json_encode($t) . ' => mb_trim: ' . json_encode(mb_trim($t)) . "\n";
}
?>
<?php
// 移除首尾 ASCII 空白 (等同 trim)
$str = " hello ";
echo preg_replace('/^\s+|\s+$/', '', $str); // hello
// 移除首尾所有 Unicode 空白 (含全形、零寬等)
echo preg_replace('/^[\p{Z}\p{C}]+|[\p{Z}\p{C}]+$/u', '', $str);
// 僅移除全形空白 U+3000
echo preg_replace('/^ +| +$/', '', $str);
// 移除首尾指定字元 (如逗號、分號)
echo preg_replace('/^[,;]+|[,;]+$/', '', ',,hello;;'); // hello
?>
<?php
function deepTrim(mixed $value): mixed {
if (is_string($value)) {
return function_exists('mb_trim') ? mb_trim($value) : trim($value);
}
if (is_array($value)) {
return array_map('deepTrim', $value);
}
if (is_object($value) && !($value instanceof \DateTimeInterface)) {
foreach ($value as $k => $v) {
$value->$k = deepTrim($v);
}
}
return $value;
}
// 使用範例:清理 $_POST
$_POST = deepTrim($_POST);
// 清理資料庫查詢結果
$users = $pdo->query('SELECT * FROM users')->fetchAll(PDO::FETCH_ASSOC);
$users = array_map('deepTrim', $users);
?>
| 陷阱 | 現象 | 解決 |
|---|---|---|
| trim() 移除中間字元 | 誤以為 trim 只移除首尾,實際上第 2 參數是「字元集合」,非「字串」 | 理解 trim($str, 'abc') 會移除首尾所有 a/b/c 字元,直到遇到非 a/b/c 為止 |
| 全形空白未移除 | 資料庫查詢 LIKE '%關鍵字%' 無法匹配前後有全形空白的資料 | 使用 mb_trim() 或 preg_replace('/^[\p{Z}]+/u', '') |
| BOM (U+FEFF) 殘留 | UTF-8 with BOM 檔案讀入後開頭有隱形字元 | mb_trim() 可移除;或檔案存儲為 UTF-8 without BOM |
| null 位元組 (\0) 殘留 | trim() 預設移除 \0,但 rtrim/ltrim 預設也移除 | 確認預設字元集包含 \0 (PHP 4.1+ 已包含) |
| 多位元組字元被截斷 | 自訂 mb_trim 實作不當導致中文字元損壞 | 使用 /u 修飾符與 \p{Z} Unicode 屬性類別 |
<?php
$str = " \t\n Hello World \r\n ";
$iterations = 1_000_000;
$start = microtime(true);
for ($i = 0; $i < $iterations; $i++) trim($str);
echo "trim: " . (microtime(true) - $start) . "s\n";
$start = microtime(true);
for ($i = 0; $i < $iterations; $i++) preg_replace('/^\s+|\s+$/', '', $str);
echo "preg_replace: " . (microtime(true) - $start) . "s\n";
$start = microtime(true);
for ($i = 0; $i < $iterations; $i++) mb_trim($str);
echo "mb_trim (polyfill): " . (microtime(true) - $start) . "s\n";
/*
典型輸出 (PHP 8.2, x64):
trim: 0.08s
preg_replace: 0.45s
mb_trim (polyfill): 0.52s
*/
?>
結論:純 ASCII 輸入用 trim() 效能最佳;含 Unicode 空白時,PHP 8.3+ 內建 mb_trim() 兼具正確與效能;舊版 PHP 使用 polyfill,效能可接受。
mb_trim()/mb_ltrim()/mb_rtrim(),完整支援 Unicode 空白。preg_replace('/^[\p{Z}\p{C}]++|[\p{Z}\p{C}]++$/u', '', $str) 實現 Unicode 感知修剪。trim()/ltrim()/rtrim()。trim($str, " \t\n\r\0\x0B,") 移除首尾空白與逗號。deepTrim() 遞迴處理陣列/物件,適用於請求輸入與資料庫結果的統一淨化。