首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 換行與跳格符號完整解析:\n、\r、\r\n、\t 跨平台差異與轉換

     編輯:PHP 相關知識

前言

字串中的換行符 (\n、\r、\r\n) 與跳格符 (\t) 在不同作業系統、編輯器、資料庫、網頁顯示中表現迥異,是資料交換、日誌分析、檔案處理的常見坑點。本文系統梳理其歷史來由、跨平台差異、PHP 中的處理方式與最佳實踐。

歷史來由:電傳打字機遺產

  • CR (Carriage Return, \r, 0x0D):將打印頭移回行首。
  • LF (Line Feed, \n, 0x0A):將紙卷向上捲一行。
  • 早期機械需同時發送 CR+LF 才能正確換行並歸位,耗時 0.2 秒(可打 2 字元)。
  • 為節省儲存空間,Unix 採用單一 LF;CP/M、DOS、Windows 採用 CR+LF;Classic Mac (OS 9 及之前) 採用 CR。

跨平台換行符對照

平台換行符十六進位常見場景
Linux / Unix / macOS (OS X+)\n (LF)0x0A伺服器、容器、Git 內部儲存
Windows (DOS 繼承)\r\n (CRLF)0x0D 0x0A記事本、Visual Studio、HTTP 標頭
Classic Mac (OS 9-)\r (CR)0x0D舊版 Mac 文字檔
HTTP 協定\r\n0x0D 0x0A標頭結束、請求/回應分隔
CSV 標準 (RFC 4180)\r\n0x0D 0x0A跨平台資料交換

PHP 中的表現與陷阱

1. 單引號 vs 雙引號 / Heredoc / Nowdoc

<?php
echo '換行: \n 輸出字面 \n';   // 單引號:不解析轉義序列
echo "換行: \n 真正換行";      // 雙引號:解析 \n \r \t 等
echo <<

2. 原始碼檔案本身的換行符

PHP 解析器接受任意換行符作為語句分隔。但版本控制 (Git) 建議統一為 LF (core.autocrlf=input),避免跨平台協作產生雜訊變更。

3. 檔案讀寫時的換行符轉換

<?php
// 讀取:fgets/fgetcsv 自動處理 \n \r\n \r (PHP 4.3+)
// 寫入:建議統一輸出 \n (Unix 風格),由儲存層/傳輸層處理轉換

// 強制轉換為 LF
$content = str_replace(["\r\n", "\r"], "\n", $content);

// 輸出 HTML 顯示:nl2br() 將 \n \r\n \r 轉 
echo nl2br($content); // 輸出 CSV/HTTP:強制 \r\n $csv_line = implode(',', $fields) . "\r\n"; header("Content-Type: text/csv; charset=utf-8"); echo $csv_line; ?>

4. 正則表達式匹配換行

<?php
// s 修飾符 (PCRE_DOTALL) 讓 . 匹配換行
preg_match('/start.*end/s', $str);        // 匹配跨行
preg_match('/^line$/m', $str);            // m 修飾符:^$ 匹配行首尾
preg_split('/\r\n|\r|\n/', $str);         // 分割所有換行類型
?>

跳格符 \t (Tab, 0x09)

  • 水平對齊、欄位分隔 (TSV)、程式碼縮排。
  • 顯示寬度取決於編輯器/終端機設定(通常 4 或 8 字元)。
  • HTML 中需轉為   或 CSS white-space: pre 保留視覺寬度。

常見互轉場景與代碼

Windows (CRLF) → Unix (LF)

<?php
// 批次轉換目錄下所有 .php .txt .css .js
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(__DIR__));
foreach ($files as $file) {
    if ($file->isFile() && in_array($file->getExtension(), ['php','txt','css','js','html'])) {
        $content = file_get_contents($file->getPathname());
        if (strpos($content, "\r\n") !== false) {
            $content = str_replace("\r\n", "\n", $content);
            file_put_contents($file->getPathname(), $content);
            echo "Converted: {$file->getPathname()}\n";
        }
    }
}
?>

資料庫匯出 CSV 強制 CRLF

<?php
$fp = fopen('php://output', 'w');
fputcsv($fp, ['ID', 'Name', 'Email'], ',', '"', "\r\n"); // 第 5 參數指定行尾 (PHP 8.1+)
// PHP 8.1 前需手動寫入
fwrite($fp, implode(',', ['ID','Name','Email']) . "\r\n");
while ($row = $stmt->fetch(PDO::FETCH_NUM)) {
    fputcsv($fp, $row, ',', '"', "\r\n");
}
fclose($fp);
?>

清理雜亂換行符(混雜 \r\n \r \n)

<?php
function normalize_line_endings(string $str, string $target = "\n"): string {
    // 先統一 \r\n → \n,再將孤立 \r → \n
    $str = str_replace("\r\n", "\n", $str);
    $str = str_replace("\r", "\n", $str);
    if ($target !== "\n") {
        $str = str_replace("\n", $target, $str);
    }
    return $str;
}

// 使用
$clean = normalize_line_endings($raw_input, "\n"); // 統一為 LF
$csv   = normalize_line_endings($raw_input, "\r\n"); // 統一為 CRLF
?>

最佳實踐總結

  1. 內部處理統一用 LF (\n):PHP 邏輯、資料庫儲存、快取、Session 皆用 LF。
  2. 輸出層按協定轉換:HTTP 標頭/CSV → CRLF;HTML → nl2br();JSON/CSV API → LF (現代標準)。
  3. Git 設定 core.autocrlf=input:提交時轉 LF,簽出時不轉,避免 Windows 開發者產生 CRLF 雜訊。
  4. 編輯器設定「換行符 = LF」:VS Code、PhpStorm、Sublime 皆可在狀態列切換。
  5. 跨平台檔案交換:提供 normalize_line_endings() 工具函數,統一轉換後再處理。

總結

理解 \n、\r、\r\n、\t 的歷史淵源與跨平台差異,並在「內部統一、邊界轉換」原則下處理,即可消除 90% 以上的換行符相關 Bug。PHP 提供 nl2br()、fgetcsv()、preg_split() 等內建工具,配合自訂 normalize_line_endings(),輕鬆應對各種檔案格式與協定需求。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved