ANSI轉義序列詳解

在這裏插入圖片描述
在這裏插入圖片描述

概念

先看ANSI_escape_code官網上的一段介紹:

In computing, ANSI escape codes (or escape sequences) are a method using in-band signaling 
to control theformatting, color, and other output options on video text terminals.To encode 
this formatting information, certain sequences of bytes are embedded into the text,which the 
terminal looks for and interprets as commands, not ascharacter codes.

在計算機系統中,ANSI轉義碼(或轉義序列)是一種使用帶內信號控制視頻文本終端的格式、顏色和其他輸出選
項的方法。爲了編碼這種格式化信息,特定的字節序列被嵌入到文本中,終端將查找並將其解釋爲命令,而不
是字符代碼。

終端,現在也叫命令行,在歷史上,確實有一種設備就叫終端。其中最爲著名的,可能就是 vt100 系列了。我們現在能看到的 terminal 軟件都是終端設備的模擬器。雖說終端設備已經作古,但終端的通信控制協議依然有效。

ANSI轉義序列就是終端上通用的通信控制協議,我們可以在命令行下顯示粗體、斜體、下劃線字符,也可以顯示不同的顏色,甚至還能顯示簡單的動畫。

ANSI序列是在二十世紀七十年代引入的標準,用以取代特定終端供應商的序列,並在二十世紀八十年代早期開始在計算機設備市場上廣泛使用。與早期缺少光標移動功能的系統相比,新生的電子公告板系統(BBS)使用ANSI序列改進其顯示。正是因爲這個原因,ANSI序列變成了所有制造商共同採用的標準。
在這裏插入圖片描述
在21世紀,儘管硬件文本終端已經越來越少了,但ANSI標準依然存在,因爲大多數終端模擬器會對部分ANSI轉義序列進行解釋。一個值得注意的例外是,在微軟Windows 10更新TH2之前,Windows操作系統的Win32控制檯是不支持ANSI轉義序列的。

歷史

最初,幾乎每個視頻終端製造商都各自添加了特定的轉義序列用於執行一些特殊操作,比如把光標置於屏幕上的某個位置。舉例來說,VT52終端允許通過發送ESC字符、y字符,後面跟上兩個等於x,y位置的數值加上32的字符(這是爲了從ASCII空格字符開始,並避開控制字符),將光標置於屏幕上的x,y位置。

由於這些序列對於不同的終端並不一樣,因此人們不得不開發了一些複雜的庫,比如termcap和實用程序,比如tput,以便程序可以使用同一套API應對各種終端。另外,在很多終端中需要藉助字符的二進制值發送數字確定光標的行和列)。對於某些編程語言,以及內部不使用ASCII的系統來說,把數字轉換爲正確的字符常常是有困難的,甚至完全做不到。

ANSI標準試圖解決這些問題。標準制訂了一種所有終端共享的指令集,並要求用ASCII的數字字符傳遞所有數值信息。該系列的第一個標準是1976年通過的ECMA-48。它是一系列字符編碼標準的延續,其中第一個是從1965年的ECMA-6,一個7位標準,ISO 646就源自此標準。“ANSI轉義序列”的名稱可以追溯到1979年ANSI採用ANSI X3.64。此外,ANSI X3L2委員會與ECMA委員會TC 1合作制訂了一個幾乎一模一樣的標準。以上兩個標準合併爲ISO 6429的國際標準。1994年,ANSI取消了其標準,以支持國際標準。

第一個支持這個標準的流行視頻終端是1978年推出的Digital VT100。這個終端在市場上非常成功,引發了各種各樣的仿製品,其中最早和最流行的是1979年的Zenith Z-19。其他品牌還有Qume QVT-108,Televideo TVI-970,Wyse WY-99GT。另外,許多其他品牌的終端也不同程度地兼容可選的“VT100”、“VT103” 或 “ANSI”模式。 隨着越來越多的軟件(尤其是BBS系統)普及,越來越多的軟件依賴轉義序列起作用,導致幾乎所有新的終端和終端模擬器都支持了此標準。

1981年,ANSI X3.64被美國政府採用(FIPS 86)。後來,美國政府停止複製行業標準,所以FIPS 86又被撤回了。

ECMA-48已經經歷了多次更新換代,當前是從1991年開始的第5版。它也被ISO和IEC用作標準ISO/IEC 6429。

支持平臺

隨着諸多BBS和線上服務廣泛使用ANSI,到20世紀80年代中期,ANSI幾乎得到了全平臺支持。儘管許多操作系統在標準文本輸出中越來越多地支持ANSI,但大多數情況下是以終端模擬器的形式(例如Unix上的xterm,或MacOS上的OS X Terminal或ZTerm,以及IBM PC上的許多通信程序)。

Unix和AmigaOS都在操作系統中包含了對ANSI的一些支持,導致在這些平臺上運行的程序廣泛使用ANSI。 類Unix操作系統可以通過像termcap和curses之類的庫來生成ANSI代碼,許多軟件使用這些庫升級顯示方式。這些庫也應該支持非ANSI終端,但是現在很少有人測試,所以很可能已經不起作用了。許多遊戲和shell腳本直接輸出ANSI序列(如彩色的提示信息),因此無法在不支持ANSI的終端上運行。

AmigaOS不僅支持輸出到屏幕上的文本使用ANSI序列,打印機驅動程序也支持(用AmigaOS的專有擴展),並將它們轉換爲與特定打印機實際通信所需的代碼。

儘管ANSI很普及,卻並沒有得到全平臺支持。比如原始的“經典”Mac OS就沒有內置對ANSI的支持,再比如Atari ST使用的是VT52改編的命令系統,用一些擴展程序支持顏色顯示。

MS-DOS 1.x不支持ANSI或任何其他轉義序列,只有少數控制字符(BEL、CR、LF、BS)可以由底層BIOS解釋,所以幾乎不可能做出任何全屏應用程序。所有顯示效果都必須通過BIOS調用,或者直接控制IBM PC硬件來完成,調用速度非常慢。

DOS 2.0引入了添加設備驅動程序來支持ANSI轉義序列的功能(事實上的標準是ANSI.SYS,但也使用了ANSI.COM、NANSI.SYS和ANSIPLUS.EXE等其他程序。因爲繞過了BIOS,所以這些程序的速度比以前快了不少)。但由於實際運行速度仍然比較慢,以及默認並沒有安裝,所以還是很少得到利用。應用程序往往還是繼續用直接控制硬件的方式來顯示所需的文本。ANSI.SYS和類似的驅動程序繼續在Windows 9x上工作,直到Windows Me,在NT派生系統中用於在NTVDM下執行的16位傳統程序。

Win32控制檯完全不支持ANSI轉義序列。不過有一些控制檯的替代品或者附加軟件具有解釋程序輸出的ANSI轉義序列的功能,例如JP Software的TCC(以前的4NT)、Michael J. Mefford的ANSI.COM、Jason Hood的ANSICON和Maximus5的ConEmu。有一個Python軟件包在內部解釋了打印文本中的ANSI轉義序列,將它們轉換爲系統調用來操縱顏色和光標位置,以便更容易地將使用ANSI的Python代碼移植到Windows。

2016年,在Windows 10發佈“Threshold 2”時,微軟開始在控制檯應用程序中支持ANSI轉義序列,使得從Unix移植軟件或者遠程訪問Unix變得更容易。

轉義序列

序列具有不同的長度。所有序列都以ASCII字符ESC(十進制的27 ,或十六進制 0x1B,或八進制的033,或轉義字符\e)開頭,第二個字節則是0x40–0x5F(ASCII 的@A–Z[]^_)範圍內的字符。

標準規定,在8位環境中,兩個字節的序列可以合併爲0x80-0x9F範圍內的單個字節(詳情請參閱C1控制字符集)。但是,在現代設備上,這些代碼通常用於其他目的,例如UTF-8的一部分或CP-1252字符,因此並不使用這種合併的方式。

除ESC之外的其他C0代碼(通常是BEL,BS,CR,LF,FF,TAB,VT,SO和SI)在輸出時也可能會產生與某些控制序列相似或相同的效果。

ANSI轉義序列C0列表
在這裏插入圖片描述
ANSI轉義序列C1不完整列表
在這裏插入圖片描述
按下鍵盤上的特殊鍵,或向終端輸出CSI、DCS或OSC請求序列,會產生從終端發送到計算機的CSI,DCS或OSC應答序列,就像用戶使用鍵盤輸入的一樣。

CSI序列

ANSI轉義序列中以 ESC [ 開頭的叫作 Control Sequence Introducer,簡寫爲 CSI。以 CSI 開頭的指令有很多,大致可分四類:光標移動指令、清屏指令、字符渲染(Graphic Rendition)指令和終端控制指令。

CSI序列由ESC [、若干個(包括0個)“參數字節”、若干個“中間字節”,以及一個“最終字節”組成。各部分的字符範圍如下:

組成部分 字符範圍 ASCII
參數字節 0x30–0x3F 0–9:;<=>?
中間字節 0x20–0x2F 空格、!"#$%&’()*+,-./
最終字節 0x40–0x7E @A–Z[]^_`a–z{

所有常見的序列都只是把參數用作一系列分號分隔的數字,如1;2;3。缺少的數字視爲0(如1;;3相當於中間的數字是0,ESC[m這樣沒有參數的情況相當於參數爲0)。某些序列(如CUU)把0視爲1,以使缺少參數的情況下有意義。

一部分字符定義是“私有”的,以便終端製造商可以插入他們自己的序列而不與標準相沖突。包括參數字節<=>?的使用,或者最終字節0x70–0x7F(p–z{|}~)例如VT320序列 CSI?25hCSI?25l 的作用是打開和關閉光標的顯示。

當CSI序列含有超出0x20–0x7E範圍的字符時,其行爲是未定義的。這些非法字符包括C0控制字符(範圍0–0x1F)、DEL(0x7F),以及高位字節。

一些CSI控制序列(不完整列表)
在這裏插入圖片描述

SGR

字符渲指令全稱 Select Graphic Rendition,簡寫爲 SGR。其格式爲 CSI n m,以數字開頭,並以 m 結尾,n 的取值範圍是 0-107。又可以分成兩類,一類控制字符顯示樣式,另一類控制顯示顏色。

SGR參數列表
在這裏插入圖片描述

顏色設置

3/4位色

初始的規格只有8種顏色,只給了它們的名字。SGR參數30-37選擇前景色,40-47選擇背景色。相當多的終端將“粗體”(SGR代碼1)實現爲更明亮的顏色而不是不同的字體,從而提供了8種額外的前景色,但通常情況下並不能用於背景色,雖然有時候反顯(SGR代碼7)可以允許這樣。

例如:

  • 在白色背景上顯示黑色文字使用ESC[30;47m,
  • 顯示紅色文字用ESC[31m,
  • 顯示明亮的紅色文字用ESC[1;31m。
  • 重置爲默認顏色用ESC[39;49m,
  • 重置所有屬性用ESC[0m。

後來的終端新增了功能,可以直接用90-97和100-107指定“明亮”的顏色。當硬件開始使用8位DAC時,多個軟件爲這些顏色名稱分配了24位的代碼。下面的圖表顯示了發送到DAC的一些常用硬件和軟件的值。

在這裏插入圖片描述

8位色

隨着256色查找表在顯卡上越來越常見,相應的轉義序列也增加了,以從預定義的256種顏色中選擇:

  • ESC[ … 38;5;n … m選擇前景色
  • ESC[ … 48;5;n … m選擇背景色
  • 0- 7:標準顏色(同ESC [ 30–37 m)
  • 8- 15:高強度顏色(同ESC [ 90–97 m)
  • 16-231:6 × 6 × 6 立方(216色): 16 + 36 × r + 6 × g + b (0 ≤ r, g, b ≤ 5)
  • 232-255:從黑到白的24階灰度色

ITU的T.416信息技術-開放文檔體系結構(ODA)和交換格式:字符內容體系結構使用“:”作爲分隔符:

  • ESC[ … 38:5:n … m選擇前景色
  • ESC[ … 48:5:n … m選擇背景色

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

24位色

隨着16位到24位顏色的“真彩色”顯卡的普及,Xterm、KDE的Konsole,以及所有基於libvte的終端(包括GNOME終端)支持了ISO-8613-3的24位前景色和背景色設置。

  • ESC[ … 38;2;<r>;<g>;<b> … m選擇RGB前景色
  • ESC[ … 48;2;<r>;<g>;<b> … m選擇RGB背景色

作爲ISO / IEC國際標準8613-6採用的ITU的T.416信息技術-開放文檔體系結構(ODA)和交換格式:字符內容體系結構給出了一個似乎不太受支持的替代版本:

  • ESC[ … 38:2:<Color-Space-ID>:<r>:<g>:<b>:<unused>:<CS tolerance>:<Color-Space: 0=“CIELUV”; 1=“CIELAB”>m選擇RGB前景色
  • ESC[ … 48:2:<Color-Space-ID>:<r>:<g>:<b>:<unused>:<CS tolerance>:<Color-Space: 0=“CIELUV”; 1=“CIELAB”>m選擇RGB背景色

請注意,這裏使用了保留的“:”字符來分隔子選項,這可能是在實際實現中造成混淆的始作俑者。它還使用“3”作爲第二個參數來指定使用青-品紅-黃方案的方案,“4”用於青-品紅-黃-黑的方案,後者使用上面標記爲“unused”的位置作爲黑色組件。

還要注意,許多識別“:”作爲分隔符的實現錯誤地忽視了色彩空間標識符參數,並因此改變了其餘部分的位置。

示例

  • CSI 2 J — 清除屏幕、(在某些設備上)把光標置於1,1位置(左上角)。

  • CSI 32 m — 使文字呈綠色。在MS-DOS上,一般綠色是暗淡的綠色,可以用CSI 1 m啓用粗體使其變成明亮的綠色,或者將兩者合併爲CSI 32 ; 1 m。MS-DOS ANSI.SYS用粗體狀態使字符變亮,閃爍狀態(通過INT 10, AX 1003h, BL 00h)使背景色變成明亮模式。MS-DOS ANSI.SYS並不直接支持SGR代碼90–97和100–107。

  • CSI 0 ; 6 8 ; “DIR” ; 13 p — 重新分配F10鍵的功能爲發送字符串“DIR”和回車符到鍵盤緩存中,在DOS命令行裏會顯示當前目錄的內容(僅MS-DOS ANSI.SYS)。這種序列有時用於“ANSI炸彈”。這是一個私用編碼(如字母p所示),用非標準的擴展使其包含一個字符串參數。如果按標準,會認爲字母D是序列的末尾。

  • CSI s — 保存光標的位置。用序列CSI u會把光標重置回這個位置。假設當前的光標位置是7(y)、10(x)。序列CSI s會保存這兩個數值。現在可以把光標移動到其他位置,比如用序列CSI 20 ; 3 H或CSI 20 ; 3 f把光標移動到20(y)、3(x)。現在如果用序列CSI u,光標會回到7(y)、10(x)。某些終端需要使用DEC序列ESC 7/ESC 8,這得到了更廣泛的支持。

主要網址

ANSI_escape_code官網地址:https://en.wikipedia.org/wiki/ANSI_escape_code
ANSI/VT100 Terminal Control Escape Sequences :http://www.termsys.demon.co.uk/vtansi.htm
xterm:https://invisible-island.net/xterm/
stackoverflow:https://stackoverflow.com/questions/4842424/list-of-ansi-color-escape-sequences

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章