學生時代玩 BBS,曾學過在純文字模式讓文字變色的小密技,但工作後開發程式以網頁、WinForm/WPF 為主,這項能力漸漸從腦中退去。這兩年愛上 CLI,寫 Console Application、PowerShell 的機會變多,重新擁抱終端機純文字模式,是時侯重拾往日技能惹。

這個技巧的學名叫 ANSI Escape Code,是一種控制字元序列,用於控制文字顯示。它們通常以 ESC (ASCII 27) 字元開始,以 m 字元結束。這些控制序列可以用於更改文字的顏色、背景色、加粗、斜體、加底線等。ANSI Escape Code 最初是為了在終端機上顯示顏色而設計,但現在它們已成為一種控制文字顯示的標準做法,並被廣泛地使用在終端機、控制台應用程式、日誌檔案等等。

例如:Chrome/Edge Console

PowerShell

Bash

ANSI Escape Code 除了顏色外,還可控制游標、切換文字輸入模式,維基百科有完整說明,這篇文章只聚焦顏色及字體格式。

控制顏色語法為 \x1b[Cm (\x1b = ASCII 27 = ESC 鍵代碼),C 值從 30 - 37 依序為 Black, Red, Green, Yellow, Magenta, Cyan, White, 90 - 97 為前述顏色的明亮版本,故基本有 16 色可運用;40 - 47 代表設為背景色,100 - 107 則為其明亮版本的背景色。另外,\x1b[C;1m 為粗體,\x1b[C;3m 為斜體,\x1b[C;4m 表加底線。切換顏色後,加上 \x1b[0m 可恢復預設顏色及字體。

像前面的例子 console.log('\x1b[91mRED\x1b[0m \x1b[92mGREEN\x1b[0m \x1b[34mBLUE\x1b[0m') 便是將前景色切為亮紅(91)、輸出文字 RED、復原,切換亮綠(92)、輸出文字 GREEN...

另外,若終端機支援 256 色,則可使用 \x1b[38;5;Nm 設定前景色、\x1b[48;5;Nm 設背景色,使用 16 色基本色、24 灰階色跟 216 種微調色。

若終端機支援 True Color,則可使用 ESC[38;2;R;G;Bm 指定 R G B 色碼,例如:\x1b[48;2;127;127;255m #7f7fff \x1b[0m。

我寫了個 C# 範例將常見用法都展示一次,方便未來查找應用。

Console.WriteLine("ANSI 顏色展示");
for (int i = 30; i < 38; i++)
{
    var code = $"\x1b[{i}m";
    Console.Write($"{code}{code.Replace("\x1b", "\\x1b")} {((ColorNames)i).ToString(),-8}\x1b[0m");
    code = $"\x1b[{i+60}m";
    Console.Write($"{code}{code.Replace("\x1b", "\\x1b")} 亮{((ColorNames)i).ToString(), -8}\x1b[0m");
    code = $"\x1b[{i};1m";
    Console.Write($"{code}{code.Replace("\x1b", "\\x1b")} 粗{((ColorNames)i).ToString(), -8}\x1b[0m");
    code = $"\x1b[{i};3m";
    Console.Write($"{code}{code.Replace("\x1b", "\\x1b")} 斜{((ColorNames)i).ToString(), -8}\x1b[0m");
    code = $"\x1b[{i};4m";
    Console.Write($"{code}{code.Replace("\x1b", "\\x1b")} {((ColorNames)i).ToString()+"底線", -9}\x1b[0m");
    code = $"\x1b[{i+10}m";
    Console.Write($" {code}{code.Replace("\x1b", "\\x1b")} {((ColorNames)i).ToString()+"底", -8}\x1b[0m");
    code = $"\x1b[{i+70}m";
    Console.Write($" {code}{code.Replace("\x1b", "\\x1b")} 亮{((ColorNames)i).ToString()+"底", -9}\x1b[0m");
    Console.WriteLine();
}

Console.WriteLine();
Console.WriteLine("256 色 \x1b[103m  \\x1b[38;5;\x1b[41mX\x1b[103mm  \x1b[0m (\x1b[33mX\x1b[0m = 0 ~ 255, 38 前景色, 48 背景色)");
Console.WriteLine("基本色 16 色");
for (int i = 0; i < 16; i++) {
    var code = $"\x1b[48;5;{i}m";
    Console.Write($"{code} {i:X2} \x1b[0m");
}
Console.WriteLine();
Console.WriteLine("216 色");
for (int i = 16; i <= 196; i += 36) {
    for (var j = 0; j < 36; j++) {
        var c = i + j;
        var code = $"\x1b[48;5;{c}m";
        Console.Write($"{code} {c:X2} \x1b[0m");
    }
    Console.WriteLine();
}
Console.WriteLine("灰階 24 色");
for (int i = 232; i < 256; i++) {
    var code = $"\x1b[48;5;{i}m";
    Console.Write($"{code} {i:X2} \x1b[0m");
}

enum ColorNames
{
    Black = 30,
    Red = 31,
    Green = 32,
    Yellow = 33,
    Blue = 34,
    Purple = 35,
    Cyan = 36,
    White = 37
}

重拾往日技能,未來就能為 Console/Shell 程式增添幾分色彩囉~

Example of using ANSI escape code to set foreground color, background color, bold, italic and underscore in Console application and shell script.


Comments

# by Anthony

本文水印 "\x16", 要全部換成 "\x1b" 第一眼睇有點違和感, 要清醒一下頭腦才能確認...

# by Jeffrey

to Anthony,寫作過程一直誤敲,有提醒自己別寫錯,最終仍不敵心魔,呵。謝謝指正。

Post a comment