使用 ANSI 跳脫序列來產生 ANSI 色彩碼有三種實用做法:手寫原始的 Select Graphic Rendition (SGR) 序列、呼叫語言專用的色彩函式庫,或使用瀏覽器式的產生器來複製帶有 ESC 前綴的原始位元組,每種做法在可移植性、透明度、與安全性之間的取捨都可以被量化衡量。將它們放在一組固定的維度上比較——實際在線上傳輸的輸出內容、實際建構位元組的位置在哪裡、誰掌控調色盤槽位、以及位元組進入日誌檔案時會發生什麼事——就能把模糊的偏好轉變成有根據的決定。SGR 格式本身是由 ECMA-48 所定義,而現今大多數終端機所實作的亮色延伸則來自 xterm 控制序列 文件。這兩份文件就是用來衡量每一種做法——無論是函式庫、手動方式或產生器——的基準真實來源。

開發者用來產生 ANSI 色彩碼的三種做法
橫跨大多數語言與執行環境,實際可行的選項可歸納為三大類。它們的差異在於位元組建構發生在哪裡、送進 stdout 的內容是什麼、以及開發者與實際的 ESC 位元組 (0x1B) 之間隔了多少抽象層。
- 手動建構 SGR。直接在字串字面值中寫出跳脫位元組、左方括號、以分號分隔的十進位參數、字母 m、文字內容、以及結尾的 ESC[0m。這是最低階的做法,也是唯一一種能從頭到尾完整呈現線路格式的方式。
- 語言專用的色彩函式庫。像是 Python 的 colorama、Node 的 chalk,或 Go 的 fatih/color 等套件,會把 SGR 數字包裝在具名常數中、處理 Windows 虛擬終端機的初始化,並代為輸出序列。
- 瀏覽器式的序列產生器。一個頁面端的工具,接收你的文字加上可選的前景、背景、粗體與底線選項,然後同時輸出原始的 ESC 序列,以及一個使用 \x1b 來代替控制位元組的可見外顯形式,讓網頁本身不會顯示色彩。
這三種做法都能有效回答「在使用 ANSI 跳脫序列時,該如何產生 ANSI 色彩碼」這個問題,但你選擇的答案會影響除錯、可移植性,以及這些位元組在日誌與聊天工具中傳遞時的安全性。
手動、函式庫與產生器做法的並列比較
當你針對程式碼離開編輯器之後才真正重要的維度為這三種做法打分數時,它們之間的差異就會變得明顯。下表以質化方式摘要這些取捨;精確的位元組序列永遠遵循 ECMA-48 與 xterm 所記載的 SGR 規則來產生。
| 維度 | 手動 SGR | 語言函式庫 | 瀏覽器式產生器 |
|---|---|---|---|
| 位元組建構在哪裡 | 在你的原始程式字串中 | 在被匯入的套件內部 | 在頁面內部,然後複製到剪貼簿 |
| 送進 stdout 的輸出 | 原始的 ESC[...m 位元組 | 原始的 ESC[...m 位元組 | 原始的 ESC[...m 位元組 (在你貼上之後) |
| Windows 主控台相容性 | 需要明確啟用 VT | 通常由函式庫處理 | 取決於目的終端機 |
| 編輯時的可見預覽 | 無 | 在原始碼中沒有,只在執行階段才會出現 | 頁面上有可見的外顯形式 |
| 若貼到日誌或聊天的風險 | 高——控制位元組原封不動地傳送 | 高——同樣是原始輸出 | 相同——複製永遠放的是原始位元組 |
| 調色盤槽位的選擇權落在哪裡 | 開發者 | 函式庫的預設值 | 開發者 (槽位編號是明確指定的) |
| 是否需要網路或上傳 | 否 | 否 (安裝後) | 否 |
開發者最容易低估的列是 Windows 相容性那一列,以及日誌風險那一列。函式庫會把這兩者都藏起來;手動序列會逼著你去思考這兩者;產生器則是把位元組交到你手上,卻無法告訴你它們最終會落在哪裡。
原始 SGR 序列在哪些地方勝過更高階的包裝層
函式庫包裝層雖然方便,卻會藏住三件在實際除錯時會反咬你一口的事情。第一,實際的 SGR 參數順序——例如 1;4;91;44 代表粗體、底線、亮紅色前景與藍色背景——在終端機行為異常時,你可能需要把它讀回來確認。第二,ESC[0m 重置是一道安全柵欄,而不是契約:某個工具可以附加它,卻仍然會發現某些消費者把粗體表現為加強亮度而不是更重的字體,或是亮色被主題重新映射。第三,當位元組離開你的程式,它們是以控制資料的身分離開,而一個在 Windows 上悄悄呼叫 init() 的包裝層,並無法保護同一段資料流不被貼到 Markdown 工單或聊天視窗中,在那些地方它可能會隱藏文字或偽造視覺上的線條。
手動序列,或是一個複製原始位元組的產生器,則把這些決定權留在你手上。ANSI Color Codes Generator 遵循這個理念:它在可見形式中把跳脫位元組顯示為 \x1b,讓網頁不會被套上樣式;並且它一定會在結尾附加一個 ESC[0m 重置,讓後續輸出比較不容易繼承樣式。精確的參數清單、順序與重置全都顯示在同一個面板中,這使得比較兩個候選做法變成讀數字,而不是讀程式碼。
使用 ANSI Color Codes Generator 建立並複製一段序列
若要快速比較手寫序列與產生器產生的序列,最快的路徑就是在瀏覽器中建立序列、複製原始位元組,然後把它與你手寫的版本並排貼上比較。這個工具會把每一個文字選擇、色彩選取、樣式開關、搜尋字詞與剪貼簿動作都保留在瀏覽器中;不會上傳任何資料,也不會在 shell 中執行任何東西。
- 在控制項中輸入終端機文字,並選擇可選的前景色彩、可選的背景色彩、粗體與底線。
- 產生序列,並在複製之前檢查可見的外顯形式 (使用 \x1b) 以及原始的 SGR 參數。
- 只把原始序列複製到可信賴且支援終端機的環境,並透過檢查同一段資料流中後續輸出是否沒有被套上樣式,來驗證重置行為。
針對前面提到的粗體、底線、亮紅色前景與藍色背景組合,產生器會輸出參數 1;4;91;44。同一組參數清單,就是手寫的 "\x1b[1;4;91;44m…\x1b[0m" 應該包含的內容,而這正是讓比較有意義的那種交叉驗證。基礎的前景碼從 30 跑到 37,背景碼從 40 跑到 47,依序為黑、紅、綠、黃、藍、洋紅、青、白;而 xterm 相容的亮色延伸則落在前景的 90 到 97,以及背景的 100 到 107。
依輸出實際呈現的位置來選擇做法
正確的做法人約上比較取決於位元組最終落在哪裡,而不是你使用的語言。一個支援 ECMA-48 與 xterm 延伸的互動式終端機,對這三種做法的容忍度一樣高,因為消費者是以同樣的方式解析位元組。至於被重新導向的非互動資料流、寫入時遵守 NO_COLOR 的檔案,或是沒有啟用虛擬終端機處理的 Windows 主控台,則會把位元組渲染成亂碼或予以忽略;在這些情況下,一個能偵測環境並優雅降級的函式庫,通常會比盲目發送的手動序列更安全。
對於日誌與聊天介面,問題已經不再是「該怎麼產生」,而是「到底該不該產生」。在把不受信任的資料列印到互動式終端機之前先進行淨化,並提供一條純文字的日誌路徑,在該路徑中控制序列會被移除或以 \x1b[.... 的形式外顯標示出來。產生器的 Copy 按鈕會把真正的原始 ESC 位元組加上 SGR 參數加上文字加上重置放到剪貼簿,而不是那四個可見字元 \x1b,因此要對待那筆剪貼簿內容,就像對待任何其他帶有控制字元的輸入一樣小心。
在真實終端機中驗證產生的序列
在兩個候選版本都能實際渲染出來之前,比較是不完整的。挑選你的使用者實際在跑的主題、多工器與輔助設定——高對比主題、SSH 內部的 tmux 或 screen,以及啟用 VT 的 Windows Terminal——是一個合理的起點矩陣,然後在該矩陣中測試每個候選序列。瀏覽器無法判斷目的端是否支援 ECMA-48、xterm 延伸、Windows 虛擬終端機處理、NO_COLOR 或重新導向輸出,所以驗證步驟必須在真實的終端機中進行,而不是在建構器中。
有用的檢查項目包括:序列在後面接著純文字時是否乾淨地重置、粗體是否真的改變字重或亮度而不是去偏移調色盤槽位、底線渲染出來是不是一條線而不是變成另一種顏色,以及亮色變體 (90–97 與 100–107) 是否如預期映射,而不是被映射成與基礎的 30–37 和 40–47 碼完全相同的重複。如果這些檢查有任何一項失敗,答案不是換工具,而是記錄是哪一組主題、多工器與目標平台的組合產生了這個差異,並在該路徑上停用色彩,或挑選另一組 SGR 參數。
比較產生 ANSI 色彩碼的各種做法,說到底就是在比較 SGR 建構發生在哪裡、誰決定調色盤槽位,以及產生的位元組能夠多安全地傳遞。ANSI Color Codes Generator 透過在同一個檢視畫面中並列顯示原始參數與可見的外顯形式,並附加 ESC[0m 重置以避免下游輸出被悄悄套上樣式,讓這場比較保持誠實。若想更深入了解參數格式本身,SGR 參數格式與安全處理 參考資料會更詳細地說明位元組結構。
若你正在權衡選項,ASCII Chart Explained: Reading All 128 Standard Codes 對此有詳細說明。