一、ASCII码
ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)最初的设计是一个7位的字符编码,使用了从0到127的数字来表示字符。这意味着它总共可以表示128个不同的字符。这包括了英文大小写字母、数字、一些标点符号以及一些控制字符(如换行、回车等)。
后来,随着计算机技术的发展和对更多字符集的需求增长,ASCII码被扩展到了8位(1个字节)。这个扩展后的版本通常称为扩展ASCII或高ASCII,并且它允许包含额外的128个字符,从而总共可以表示256个字符。这些额外的字符集通常用来表示其他符号、控制代码,以及其他语言的特殊字符。
ASCII 字符集中的数字0到31以及数字127对应的是控制字符(control characters),也被称为非打印字符(non-printing characters)。它们不代表可视化的字符,而是用来控制文本的传输和显示行为。以下是一些常见控制字符的描述:
0
(NUL
): 空字符 (Null character),经常用于标记字符串的结束。1
(SOH
): 标题开始 (Start of Header),用于通信协议中的消息开始。2
(STX
): 正文开始 (Start of Text),标记文本实际内容的开始。3
(ETX
): 正文结束 (End of Text),通常标记传输结束。4
(EOT
): 传输结束 (End of Transmission),用于终止一个传输序列。5
(ENQ
): 询问字符 (Enquiry),用于请求远端发送响应。6
(ACK
): 确认字符 (Acknowledge),是对接收数据成功的响应。7
(BEL
): 响铃 (Bell),当解释此字符时会发出声音或视觉信号。8
(BS
): 退格 (Backspace),使光标向左移动一位。9
(HT
): 水平制表符 (Horizontal Tab),用于控制文本的横向间隔。10
(LF
): 换行 (Line Feed),在Unix和Unix-like系统中用于开始新的一行。11
(VT
): 垂直制表符 (Vertical Tab),用于控制文本的纵向间隔。12
(FF
): 走纸换页 (Form Feed),在打印机中用来将纸张推进到下一页的位置。13
(CR
): 回车 (Carriage Return),在Mac OS之前和Windows系统中用于返回行首,并在Windows中与LF
一起组合使用来开始新的一行。14
(SO
): 移位输出 (Shift Out),用于临时切换到另一套字符集。15
(SI
): 移位输入 (Shift In),用于返回标准字符集。16
到31
: 其他控制功能,包括文件分隔、组分隔、记录分隔等。127
(DEL
): 删除 (Delete),用于删除前一个字符,通常是逻辑删除而非物理删除。
这些控制字符在现代文本编辑和显示中通常不经常直接使用,但在通信协议、文件格式和程序语言中仍发挥作用。例如,LF
和 CR
在不同操作系统中的文本文件中作为换行的标记。而 NUL
字符经常用在某些编程语言中表示字符串的终止。
下面是ASCII码的详细对比表格,蓝色的是控制字符,没有填充色彩的是可显示字符。
二、ANSI转义序列
ANSI是(American National Standards Institute)的缩写。控制字符的数量限制使得它们不足以满足控制现代终端设备的所有需求,特别是在文本格式化和复杂的界面控制方面。为了解决这个问题,引入了转义序列这一概念,它允许使用更复杂的指令来控制终端的行为。
大部分情况下,ANSI转义序列都是以 ESC 开头的,所以是(ANSI escape codes)或者(ANSI escape sequences)。
1、ANSI转义序列C0列表:
这些是控制字符,用于文本处理中的特殊功能,如回车(CR)、换行(LF)等。这些字符的代码通常在ASCII的0x00到0x1F范围内。
也就是上面的表格的控制字符:
2、ANSI转义序列C1列表
C1控制字符用于扩展的文本控制目的,比如开始定向控制(SDC)或单字符强调(SCI)。这些字符的代码范围通常是0x80到0x9F。
序列符号 | 码值 | 名称 | 作用 |
---|---|---|---|
ESC N | 0x8e | SS2-Single Shift Two | 用来从替代字符集中选择字符。在兼容ANSI的系统中,SS2通常用来临时切换到G2字符集,以访问特殊字符。 |
ESC O | 0x8f | SS3-Single Shift Three | 用来从替代字符集中选择字符。在兼容ANSI的系统中,SS3用于临时切换到G3字符集。 |
ESC P | 0x90 | DCS-Device Control String | 用于传输设备控制信息,这些信息被设备或终端用来执行特定的硬件控制功能,例如,xterm中可能用来定义键位映射或请求设置。 |
ESC [ | 0x9b | CSI-Control Sequence Introducer | 用于引入一系列控制序列,它结束于ASCII 64到126之间的字符。此序列用于多种光标和显示控制操作。 |
ESC \ | 0x9c | ST-String Terminator | 终止一个控制字符串,如APC、DCS、OSC、PM和SOS这样的序列。 |
ESC ] | 0x9d | OSC-Operating System Command | 用于传输操作系统级别的命令或请求,如设置窗口标题或其他属性。在xterm中,这些控制序列可以由ST终止,或者通常也可以由BEL终止。 |
ESC X | 0x98 | SOS-Start of String | 用来标记一个控制字符串的开始,这个字符串不是用来被终端直接处理,而是作为私有消息传递给应用程序。 |
ESC ^ | 0x9e | PM-Privacy Message | 用于传输私有消息,这些消息不应该被记录或存储,用于敏感信息传输。 |
ESC _ | 0x9f | APC-Application Program Command | 用于传输应用程序命令,这些命令通常由特定的软件应用来解释和执行。 |
ESC c | 0x1b c | RIS-Reset to Initial State | 用于将终端或设备重置到其初始状态。可能包括重置图形属性、清除制表符、恢复默认字体等。 |
ANSI转义序列中的C1控制字符确实有其自己的范围,这些字符的代码通常在0x80到0x9F之间。不过,这些并不属于原始的7位ASCII码,而是属于扩展的8位字符集。原始的ASCII码只定义了0x00到0x7F的字符。
在8位字符集中,0x80到0x9F的部分被用于C1控制字符,它们主要在一些特定的编码和协议中使用,如ISO/IEC 8859和Windows-1252。这些字符在不同环境下的解释和使用可能会有区别。例如,在标准的ISO 8859-1编码中,这个范围内的字符是不可见的控制字符,而在Windows-1252编码中,部分字符被映射为可打印字符。
这些C1控制字符最初是为了多媒体、复杂文本布局和其他特殊用途而设计的。在现代系统中,它们的使用较少,相比之下,更常用的控制字符集是C0集合,尤其是在基于文本的界面和协议中。
3、Control Sequence Introducer(CSI)序列
Control Sequence Introducer(CSI)序列是ANSI转义序列的一部分,就是上面ANSI转义序列C1列表背景为蓝色的一行,用于更加复杂的终端控制,如光标移动、文本格式设置、颜色变化等。CSI序列通常以(ESC,ASCII码为十进制的27 ,或十六进制 0x1B,或八进制的033,或转义字符\e)和左方括号[
开头,紧跟着是参数字节、中间字节(如果有的话),并以最终字节结束。终端设备接收到转义符后,会预期接下来的字符形成一个完整的转义序列,并根据这些序列来执行相应的操作,而不是将这些字符显示在屏幕上。
ESC [ 参数字节 ; 参数字节 ... 中间字节 最终字节
- ESC [:这两个字符是CSI序列的引导符,用于开始这个序列。
- 参数字节:这些通常是数字字符,用于提供具体的参数,如光标位置、颜色代码或其他选项。参数之间可以用分号
;
分隔。 - 中间字节:这部分是可选的,用于进一步控制或区分操作。
- 最终字节:表示CSI序列的结束,并触发终端执行相应的命令。这通常是ASCII码表中的
@
到~
之间的字符。
组成部分 | 字符范围 | ASCII |
---|---|---|
参数字节 | 0x30–0x3F | 0–9:;<=>? |
中间字节 | 0x20–0x2F | space、!"#$%&'()*+,-./ |
最终字节 | 0x40–0x7E | @A–Z[\]^_ a–z{ |
CSI(Control Sequence Introducer)控制序列用于在终端中执行各种控制操作,例如移动光标、修改文本属性、清除屏幕等。解释:
-
参数的使用:CSI序列通常包含一系列参数,这些参数用分号分隔。例如,CSI序列可能是这样的形式:
CSI Pn1;Pn2;...;PnN Ps1;Ps2;...;PsM C
,其中Pn1;Pn2;...;PnN
是数值参数,Ps1;Ps2;...;PsM
是选择参数。如果某个参数缺失,通常被视为0。例如,CSI 1;;3
中间的分号表示缺少参数,相当于CSI 1;0;3
,即参数为1、0、3。 -
参数缺失情况下的默认值:某些情况下,缺少参数可能会被解释为默认值,例如
CUU
命令(向上移动光标),如果没有参数,通常会被解释为向上移动一个字符。所以,CSI A
通常等同于CSI 1 A
,即向上移动一个字符。 -
私有字符定义:一些CSI序列可能是私有的,这样终端制造商可以定义自己的控制序列而不与标准冲突。例如,
CSI?25h
和CSI?25l
序列用于打开和关闭光标显示,其中?25
是私有序列,终端制造商可以根据自己的需求定义。 -
非法字符:如果CSI序列包含了超出规定范围的字符,其行为是未定义的。这些非法字符包括C0控制字符(0x00–0x1F)、DEL(0x7F),以及高位字节。
对于上面的最终字节一般会决定这个CSI序列的功能,然后参数字节和中间字节是对于后面的最终字节的参数,确定最终字节决定的功能的细节。可以在下面的列表中看到这些的体现。
下面是CSI的一些序列列表:
代码 | 名称 | 作用 |
---|---|---|
CSI n A | CUU - 光标上移 | 将光标向上移动n个字符位置。如果n未指定,默认为1。如果光标已在屏幕边缘,则不执行任何操作。 |
CSI n B | CUD - 光标下移 | 将光标向下移动n个字符位置。如果n未指定,默认为1。 |
CSI n C | CUF - 光标前移 | 将光标向前移动n个字符位置。如果n未指定,默认为1。 |
CSI n D | CUB - 光标后移 | 将光标向后移动n个字符位置。如果n未指定,默认为1。 |
CSI n E | CNL - 光标移到下一行 | 将光标移动到下一行的开头,并向下移动n-1行。如果n未指定,默认为1。 (非ANSI.SYS) |
CSI n F | CPL - 光标移到上一行 | 将光标移动到上一行的开头,并向上移动n-1行。如果n未指定,默认为1。 (非ANSI.SYS) |
CSI n G | CHA - 光标水平绝对 | 将光标移动到当前行的第n列位置。如果n未指定,默认为1。 (非ANSI.SYS) |
CSI n;mH | CUP - 光标位置 | 将光标移动到第n行第m列的位置。如果n或m未指定,默认为1。 |
CSI n J | ED - 擦除显示 | 用于清除屏幕的部分区域。 |
CSI n K | EL - 擦除行 | 用于清除当前行的部分区域。 |
CSI n S | SU - 向上滚动 | 将整页内容向上滚动n行。新行添加到底部。(非ANSI.SYS) |
CSI n T | SD - 向下滚动 | 将整页内容向下滚动n行。新行添加到顶部。(非ANSI.SYS) |
CSI n;mf | HVP - 水平垂直位置 | 将光标移动到第n行第m列的位置,与CUP相同。 |
CSI n m | SGR - 选择图形再现 | 设置图形再现参数,包括文字颜色。 |
CSI 5i | 打开辅助端口 | 启用辅助串行端口,通常用于本地串行打印机。 |
CSI 4i | 关闭辅助端口 | 禁用辅助串行端口,通常用于本地串行打印机。 |
CSI 6n | DSR - 设备状态报告 | 向应用程序报告光标位置(CPR),其中n是行,m是列。 |
CSI s | SCP - 保存光标位置 | 保存当前光标位置。 |
CSI u | RCP - 恢复光标位置 | 恢复之前保存的光标位置。 |
表格中的CSI可以换成 ESC(ASCII码为十进制的27 ,或十六进制 0x1B,或八进制的033,或转义字符\e) 加上 [ 。
一些常用的CSI序列:
转义字符 | 说明 |
---|---|
\033[0m | 关闭所有属性 |
\033[1m | 设置高亮度 |
\033[4m | 下划线 |
\033[5m | 闪烁 |
\033[7m | 反显 |
\033[8m | 消隐 |
\033[30m-\33[37m | 设置前景颜色 |
\033[40m-\33[47m | 设置背景颜色 |
\033[nA | 光标上移n行 |
\033[nB | 光标下移n行 |
\033[nC | 光标右移n行 |
\033[nD | 光标左移n行 |
\033[y;xH | 设置光标位置 |
\033[2J | 清屏 |
\033[K | 清除从光标到行尾的内容 |
\034[s | 保存光标位置 |
\033[u | 恢复光标位置 |
\033[?25l | 隐藏光标 |
\033[?25h | 显示光标 |
4、SGR(Select Graphic Rendition)选择图形再现参数
1)SGR介绍
SGR(Select Graphic Rendition)是一种 ANSI 转义码序列,同样也是上面的 CSI 序列的一种,就是上面 CSI 序列表格中背景为蓝色的一行,用于在文本终端中设置文本属性,包括颜色、样式和其他外观效果。它允许开发者控制文本在终端上的呈现方式,从而创建出更丰富多彩的用户界面和输出效果。
SGR 序列由 ESC(Escape)字符后跟着零个或多个以分号分隔的参数组成,然后以字母 "m" 结束。参数用于指定要应用的不同文本属性,例如颜色、粗体、斜体等。每个参数都对应一个特定的文本属性,可以单独使用,也可以组合在一起以实现复杂的效果。
2)SGR参数
SGR(Select Graphic Rendition)选择图形再现参数表格:
代码 | 作用 | 备注 |
---|---|---|
0 | 重置/正常 | 关闭所有属性。 |
1 | 粗体或增加强度 | |
2 | 弱化(降低强度) | 未广泛支持。 |
3 | 斜体 | 未广泛支持。有时视为反相显示。 |
4 | 下划线 | |
5 | 缓慢闪烁 | 低于每分钟150次。 |
6 | 快速闪烁 | MS-DOS ANSI.SYS;每分钟150以上;未广泛支持。 |
7 | 反显 | 前景色与背景色交换。 |
8 | 隐藏 | 未广泛支持。 |
9 | 划除 | 字符清晰,但标记为删除。未广泛支持。 |
10 | 主要(默认)字体 | |
11–19 | 替代字体 | 选择替代字体。 |
20 | 尖角体 | 几乎无支持。 |
21 | 关闭粗体或双下划线 | 关闭粗体未广泛支持;双下划线几乎无支持。 |
22 | 正常颜色或强度 | 不强不弱。 |
23 | 非斜体、非尖角体 | |
24 | 关闭下划线 | 去掉单双下划线。 |
25 | 关闭闪烁 | |
27 | 关闭反显 | |
28 | 关闭隐藏 | |
29 | 关闭划除 | |
30–37 | 设置前景色 | 参见下面的3位色。 |
38 | 设置前景色 | 下一个参数是5;n(8位色)或2;r;g;b(24位色),两种参数形式,参见下面的8位色和24位色。 |
39 | 默认前景色 | 由具体实现定义(按照标准)。 |
40–47 | 设置背景色 | 参见下面的3位色。 |
48 | 设置背景色 | 下一个参数是5;n(8位色)或2;r;g;b(24位色),两种参数形式,参见下面的8位色和24位色。 |
49 | 默认背景色 | 由具体实现定义(按照标准)。 |
51 | Framed | |
52 | Encircled | |
53 | 上划线 | |
54 | Not framed or encircled | |
55 | 关闭上划线 | |
60 | 表意文字下划线或右边线 | 几乎无支持。 |
61 | 表意文字双下划线或双右边线 | |
62 | 表意文字上划线或左边线 | |
63 | 表意文字双上划线或双左边线 | |
64 | 表意文字着重标志 | |
65 | 表意文字属性关闭 | 重置60–64的所有效果。 |
90–97 | 设置明亮的前景色 | aixterm(非标准)。参见下面的4位颜色。 |
100–107 | 设置明亮的背景色 | aixterm(非标准)。参见下面的4位颜色。 |
3)3位(不包括后面的明亮颜色)或4位色基本颜色代码:
前景色:
SGR参数 | 颜色 | 明亮颜色(粗体) |
---|---|---|
30 | 黑色 | 90(明亮黑色) |
31 | 红色 | 91(明亮红色) |
32 | 绿色 | 92(明亮绿色) |
33 | 黄色 | 93(明亮黄色) |
34 | 蓝色 | 94(明亮蓝色) |
35 | 品红 | 95(明亮品红) |
36 | 青色 | 96(明亮青色) |
37 | 白色 | 97(明亮白色) |
背景色:
SGR参数 | 颜色 | 明亮颜色(粗体) |
---|---|---|
40 | 黑色背景 | 100(明亮黑色背景) |
41 | 红色背景 | 101(明亮红色背景) |
42 | 绿色背景 | 102(明亮绿色背景) |
43 | 黄色背景 | 103(明亮黄色背景) |
44 | 蓝色背景 | 104(明亮蓝色背景) |
45 | 品红背景 | 105(明亮品红背景) |
46 | 青色背景 | 106(明亮青色背景) |
47 | 白色背景 | 107(明亮白色背景) |
颜色卡(这里是使用Microsoft Visual Studio 调试控制台得到的,不同平台可能不一样):
实例:
#include <stdio.h>
int main() {
// 黑色文字,红色背景
printf("\033[30;41mBlack text on Red background\033[0m\n");
// 明亮蓝色文字,黄色背景
printf("\033[1;34;43mBright Blue text on Yellow background\033[0m\n");
// 明亮白色文字,品红背景
printf("\033[1;37;45mBright White text on Magenta background\033[0m\n");
return 0;
}
运行结果:
小特性:
对于这里的参数,如果在printf这类格式化打印的函数中甚至可以实现这样:
int num = 46;
printf("\033[%dm \033[0m\n", num);
运行结果:
这里的参数使用printf格式化字符串的特性,利用printf后面的参数来改变这里的参数。可以利用 printf 函数的格式化字符串功能以及后续的参数来动态地改变 ANSI 转义序列中的值。同时这里还有一个现象,就是设置好背景色后再打印空格,就可以打印一定长度的色块。
一般在printf中使用 \033[1;37;45m 之类的转义字符来对打印内容的前景和背景的颜色进行调整后,要再次使用 \033[0m 转义字符来重置所有属性,以防对后面的颜色调整产生影响。
可以发现这里的转义序列可以同时对多个属性进行调整,例如 \033[1;37;45m 同时设置粗体(明亮)字体、白色前景(字体)和品红背景三个属性。
8位色提供了更广泛的颜色选择,让开发者可以从256种预定义的颜色中选择。这是一种更灵活的颜色控制方式,允许更细粒度地定义所需的颜色。
下面介绍8位色和24位色:
在8位色或24位色的情况下决定前景和背景与决定颜色的代码分开了,先使用38(前景)或48(背景)确定下面的颜色参数是设置前景还是背景。
当在38或48之后使用参数时,可以使用以下两种格式之一:
-
5;n:这种格式用于选择256色调色板中的颜色,也就是8位色。其中,n是0到255之间的整数,对应于预定义的颜色索引。
-
2;r;g;b:这种格式用于指定RGB颜色,也就是24位色。其中,r、g和b是0到255之间的整数,分别代表红、绿和蓝的亮度值。
例如,要选择256色调色板中的第200种颜色,可以使用ESC[38;5;200m
。要选择RGB颜色(255, 0, 128),可以使用ESC[38;2;255;0;128m
。
4)8位色
格式:
- 前景色:
ESC[38;5;n ... m
- 背景色:
ESC[48;5;n ... m
参数38确定是设置前景色,参数48确定是设置背景色。其中,n是0到255之间的整数,对应于预定义的颜色索引,...代表其他参数,m是结束字符。
颜色范围:
8位色提供了256种不同的颜色,范围从0到255。这些颜色包括:
- 0-7:标准颜色,与ANSI标准的30-37前景色和40-47背景色相对应。
- 8-15:高强度颜色,通常与标准颜色的亮度略有不同,与ANSI标准的90-97前景色和100-107背景色相对应。
- 16-231:这个范围内的颜色是通过一种计算方法生成的,可以产生216种颜色。它们的色彩是由RGB色彩立方体中的各种组合生成的,其中红、绿和蓝的值各有6个等级。
具体的计算公式为:,其中:( r, g, b ) 分别是红色、绿色和蓝色的强度值,每种颜色的强度值范围从0到5。这个公式允许每种颜色分量(红、绿、蓝)独立地选择从0到5的六个强度级别,也就是说(0 ≤ r,g,b ≤ 5),从而可以生成216种不同的颜色组合。
- 232-255:这个范围内的颜色是从黑色到白色的24阶灰度色。
颜色卡(这里是使用Microsoft Visual Studio 调试控制台得到的,不同平台可能不一样):
使用示例:
- 选择第200种颜色作为前景色:
ESC[38;5;200m
- 选择第50种颜色作为背景色:
ESC[48;5;50m
- 同时进行前景和背景的设置:
ESC[38;5;200;48;5;50m
实例:
#include <stdio.h>
int main()
{
// 前景色为天蓝色(索引 33),背景色为浅灰色(索引 249)
printf("\x1b[38;5;33;48;5;249mThis text has sky blue foreground and light grey background.\x1b[0m\n");
// 前景色为深红色(索引 124),背景色为奶油色(索引 230)
printf("\x1b[38;5;124;48;5;230mThis text has deep red foreground and cream background.\x1b[0m\n");
// 前景色为粉红色(索引 211),背景色为深绿色(索引 22)
printf("\x1b[38;5;211;48;5;22mThis text has pink foreground and dark green background.\x1b[0m\n");
// 前景色为柠檬色(索引 190),背景色为深蓝色(索引 19)
printf("\x1b[38;5;190;48;5;19mThis text has lemon foreground and navy blue background.\x1b[0m\n");
// 前景色为橙色(索引 208),背景色为淡蓝色(索引 153)
printf("\x1b[38;5;208;48;5;153mThis text has orange foreground and light blue background.\x1b[0m\n");
return 0;
}
运行结果:
5)24位色(Ture color真彩色)
格式:
- 前景色:ESC[38;2;r;g;bm
- 背景色:ESC[48;2;r;g;bm
颜色范围:
在24位色格式中,每个颜色通道(红、绿和蓝)都有8位,允许的值范围是0到255。这意味着每个颜色通道可以有256种可能的亮度级别。因此,总的颜色可能性是256 × 256 × 256 = 16,777,216种可能的颜色。
由于24位色有16,777,216种可能的颜色,这里就不给出颜色卡了,网上有很多网站可以查看24位色代码对应的颜色。
使用示例:
- 前景设置为明亮的蓝色(RGB值为0, 120, 215)ESC[38;2;0;120;215m
- 背景设置为柔和的粉红色(RGB值为255, 182, 193)ESC[48;2;255;182;193m
- 同时设置前景和背景色 ESC[38;2;0;120;215;48;2;255;182;193m
实例:
#include <stdio.h>
int main()
{
//桃色文本,薄荷绿背景:
printf("\033[38;2;255;128;128m\033[48;2;64;255;170m Hello, World! \033[0m\n");
//天蓝色文本,橙色背景:
printf("\033[38;2;135;206;235m\033[48;2;255;165;0m Hello, World! \033[0m\n");
//淡紫色文本,淡金色背景:
printf("\033[38;2;216;191;216m\033[48;2;255;223;0m Hello, World! \033[0m\n");
//橄榄绿文本,淡灰色背景:
printf("\033[38;2;128;128;0m\033[48;2;211;211;211m Hello, World! \033[0m\n");
//深粉色文本,海蓝色背景:
printf("\033[38;2;255;20;147m\033[48;2;95;158;160m Hello, World! \033[0m\n");
return 0;
}
运行结果:
并非所有的终端或命令行界面都支持所有的颜色和ANSI转义序列,这取决于你的终端程序和它的配置。而且尽管 ANSI 色彩代码是一个标准,但由于不同平台和终端的实现方式和支持程度不同,导致了颜色在不同平台上的显示可能会有所差异。