`substr_replace()` 可在指定位置替換字串片段,支援正負索引、長度控制,適合**截斷過長字串加省略號**、**金額加千分位**、**模板標記替換**等場景。
substr_replace(string $string, string $replace, int $offset, int $length = strlen($string)): string
<?php
function truncateMiddle(string $str, int $maxLen = 50, string $ellipsis = '...'): string {
$len = mb_strlen($str, 'UTF-8');
if ($len <= $maxLen) return $str;
$keep = $maxLen - mb_strlen($ellipsis);
$start = (int)($keep / 2); // 前半保留
$endKeep = $keep - $start; // 後半保留
$first = mb_substr($str, 0, $start, 'UTF-8');
$last = mb_substr($str, -$endKeep, null, 'UTF-8');
// 計算位元組偏移 (substr_replace 操作位元組)
$firstBytes = mb_strlen($first, '8bit');
$lastBytes = mb_strlen($last, '8bit');
$totalBytes = mb_strlen($str, '8bit');
$replaceLen = $totalBytes - $firstBytes - $lastBytes;
return substr_replace($str, $ellipsis, $firstBytes, $replaceLen);
}
$long = 'abcdefghijklmnopqrstuvwxyz0123456789z.jpg';
echo truncateMiddle($long, 25); // abcdefghijk...456789z.jpg
?>
<?php
function truncateWords(string $text, int $maxLen, string $ellipsis = '...'): string {
$text = html_entity_decode($text, ENT_QUOTES, 'UTF-8');
if (mb_strlen($text, 'UTF-8') <= $maxLen) return $text;
// 先粗略截斷
$text = mb_substr($text, 0, $maxLen, 'UTF-8');
// 回退到最後一個空白
$lastSpace = mb_strrpos($text, ' ', null, 'UTF-8');
if ($lastSpace !== false) {
$text = mb_substr($text, 0, $lastSpace, 'UTF-8');
}
// 移除結尾標點
$text = rtrim($text, ".,;:!?。,、;:!?");
return $text . $ellipsis;
}
$txt = 'welcome to bkjia, welcome to bkjia, welcome to bkjia';
echo truncateWords($txt, 35); // welcome to bkjia, welcome to...
?>
<?php
function numberFormatComma(string $num): string {
// 處理小數部分
if (($pos = strpos($num, '.')) !== false) {
$intPart = substr($num, 0, $pos);
$decPart = substr($num, $pos);
} else {
$intPart = $num;
$decPart = '';
}
// 從右往左插入
$len = strlen($intPart);
for ($i = $len - 3; $i > 0; $i -= 3) {
$intPart = substr_replace($intPart, ',', $i, 0);
}
return $intPart . $decPart;
}
echo numberFormatComma('163000'); // 163,000
echo numberFormatComma('1234567.89'); // 1,234,567.89
// 實際專案建議用 number_format() 或 NumberFormatter
?>
<?php
function renderTemplate(string $tpl, array $data): string {
foreach ($data as $key => $val) {
$placeholder = '{{' . $key . '}}';
$pos = 0;
while (($pos = strpos($tpl, $placeholder, $pos)) !== false) {
$tpl = substr_replace($tpl, $val, $pos, strlen($placeholder));
$pos += strlen($val); // 移至替換內容後,避免重複掃描
}
}
return $tpl;
}
$tpl = 'Hello {{name}}, your order {{order_id}} is {{status}}.';
$data = ['name' => 'John', 'order_id' => '20240101001', 'status' => 'shipped'];
echo renderTemplate($tpl, $data);
// Hello John, your order 20240101001 is shipped.
?>
| 議題 | 說明 | 對策 |
|---|---|---|
| 多字元字串 (UTF-8) | `substr_replace` 操作**位元組**,中文會導致亂碼 | 配合 `mb_substr` 計算位元組偏移,或改用 `mbstring` 系列函式 |
| 大量替換 | 每次呼叫複製整字串,記憶體峰值高 | 收集替換位置最後一次處理、或用 `strtr` (單次掃描) |
| 負數 offset/length | 從結尾計算,直觀但易誤解 | 註解清楚、單元測試覆蓋邊界 |