ANSI转义码是一种终端控制协议,通过在文本流中插入特殊的字符序列来控制终端的显示行为,包括文本颜色、光标移动、屏幕清除等高级功能。
1. 基础概念
1.1 组成结构
- 转义字符 :通常使用
\x1b或\033表示 - 控制序列引导符 :通常是
[ - 参数字符 :用分号
;分隔的参数 - 结束符:表示命令类型的字符
每个ANSI转义序列都以转义字符(ESC,ASCII 27)作为开始。 \033 是以 8进制 的形式代表着 10进制数 :27, 通过对照 ASCII表 不难找出,其为不可见 ASCII 字符 : ESC (1B 位置,因为 27 的十六进制数为 0x1B );也就是转义(Escape)的意思。

1.2 基本格式
格式: ESC [ parameters command
示例: \x1b[31m (设置为红色)
[31m 中的 31 对应区间为 30-37, 因此代表的是前景色;从下面的表格 中可得知:31代表的是红色。

2. 光标控制命令
| 命令 | 代码 | 说明 |
|---|---|---|
| 光标上移 | \x1b[{n}A |
光标上移n行 |
| 光标下移 | \x1b[{n}B |
光标下移n行 |
| 光标右移 | \x1b[{n}C |
光标右移n列 |
| 光标左移 | \x1b[{n}D |
光标左移n列 |
| 光标下移行首 | \x1b[{n}E |
光标下移n行到行首(CSI n E) |
| 光标上移行首 | \x1b[{n}F |
光标上移n行到行首(CSI n F) |
| 设置光标位置 | \x1b[{n};{m}H |
将光标移动到第n行第m列 |
| 光标水平绝对 | \x1b[{n}G |
光标移动到当前行的第n列 |
| 保存光标位置 | \x1b[s |
保存当前光标位置 |
| 恢复光标位置 | \x1b[u |
恢复保存的光标位置 |
3. 屏幕清除命令
| 命令 | 代码 | 说明 |
|---|---|---|
| 清除光标到屏末 | \x1b[0J 或 \x1b[J |
清除从光标位置到屏幕末尾的内容 |
| 清除屏首到光标 | \x1b[1J |
清除从屏幕开头到光标位置的内容 |
| 完全清除屏幕 | \x1b[2J |
清除整个屏幕并将光标移至(0,0) |
| 清除当前行 | \x1b[K |
清除从光标位置到行末的内容 |
| 清除光标到行首 | \x1b[1K |
清除从行首到光标位置的内容 |
| 清除整行 | \x1b[2K |
清除整行内容 |
4. 文本属性命令
| 命令 | 代码 | 说明 |
|---|---|---|
| 重置所有属性 | \x1b[0m |
重置所有属性为默认值 |
| 粗体/高亮 | \x1b[1m |
设置文本为粗体或高亮 |
| 弱化/低强度 | \x1b[2m |
设置文本为淡色或低强度 |
| 斜体 | \x1b[3m |
设置文本为斜体 |
| 下划线 | \x1b[4m |
添加下划线 |
| 慢速闪烁 | \x1b[5m |
设置文本慢速闪烁 |
| 快速闪烁 | \x1b[6m |
设置文本快速闪烁 |
| 反转视频 | \x1b[7m |
交换前景色和背景色 |
| 隐藏文本 | \x1b[8m |
设置文本隐藏 |
| 删除线 | \x1b[9m |
添加删除线 |
5. 颜色控制
5.1 基本前景色(30-37)
| 颜色 | 代码 | 颜色 | 代码 |
|---|---|---|---|
| 黑色 | \x1b[30m |
红色 | \x1b[31m |
| 绿色 | \x1b[32m |
黄色 | \x1b[33m |
| 蓝色 | \x1b[34m |
品红 | \x1b[35m |
| 青色 | \x1b[36m |
白色 | \x1b[37m |
| 默认 | \x1b[39m |
5.2 基本背景色(40-47)
| 颜色 | 代码 | 颜色 | 代码 |
|---|---|---|---|
| 黑色 | \x1b[40m |
红色 | \x1b[41m |
| 绿色 | \x1b[42m |
黄色 | \x1b[43m |
| 蓝色 | \x1b[44m |
品红 | \x1b[45m |
| 青色 | \x1b[46m |
白色 | \x1b[47m |
| 默认 | \x1b[49m |
5.3 高亮前景色(90-97)
| 颜色 | 代码 | 颜色 | 代码 |
|---|---|---|---|
| 亮黑 | \x1b[90m |
亮红 | \x1b[91m |
| 亮绿 | \x1b[92m |
亮黄 | \x1b[93m |
| 亮蓝 | \x1b[94m |
亮品红 | \x1b[95m |
| 亮青 | \x1b[96m |
亮白 | \x1b[97m |
5.4 高亮背景色(100-107)
| 颜色 | 代码 | 颜色 | 代码 |
|---|---|---|---|
| 亮黑 | \x1b[100m |
亮红 | \x1b[101m |
| 亮绿 | \x1b[102m |
亮黄 | \x1b[103m |
| 亮蓝 | \x1b[104m |
亮品红 | \x1b[105m |
| 亮青 | \x1b[106m |
亮白 | \x1b[107m |
5.5 同时设置前景和背景色
通过在 \033[ 后面用分号 ; 分隔多个参数,即可同时指定前景色和背景色。例如:
-
前景色红色(31) + 背景色黄色(43) :
\033[31;43m文本内容\033[0m -
前景色白色(37) + 背景色蓝色(44) :
\033[37;44m文本内容\033[0m
示例程序:
cpp
#include <stdio.h>
int main(void)
{
int i, j, n;
printf("\n");
printf("\n");
for (i = 0; i < 11; i++)
{
for (j = 0; j < 10; j++)
{
n = 10 * i + j;
if (n > 108)
break;
printf(" \033[%dm %3d\033[m", n, n);
}
printf("\n");
}
printf("\n");
printf("\n");
return 0;
}
程序输出:

6. 256色模式
6.1 前景色(38)
格式: \x1b[38;5;{n}m
示例: \x1b[38;5;196m (红色)
6.2 背景色(48)
格式: \x1b[48;5;{n}m
示例: \x1b[48;5;27m (蓝色背景)
注意:大多数现代终端都支持256色,但不是所有终端都支持。对于更好的终端,还可以使用24位真彩色。

7. 真彩色模式(24位)
7.1 RGB前景色
格式: \x1b[38;2;{r};{g};{b}m
示例: \x1b[38;2;255;128;0m (橙色)
7.2 RGB背景色
格式: \x1b[48;2;{r};{g};{b}m
示例: \x1b[48;2;0;128;255m (蓝色背景)
8. 滚动与屏幕控制
| 命令 | 代码 | 说明 |
|---|---|---|
| 屏幕保存 | \x1b[?1049h |
保存屏幕并切换到备用缓冲区 |
| 屏幕恢复 | \x1b[?1049l |
恢复保存的屏幕 |
| 滚动区域设置 | \x1b[{t};{b}r |
设置滚动的顶部和底部行 |
| 滚动上移 | \x1b[{n}S |
整个屏幕向上滚动n行 |
| 滚动下移 | \x1b[{n}T |
整个屏幕向下滚动n行 |
9. 实用功能
9.1 标题设置
text
格式: \x1b]2;{title}\x07
示例: \x1b]2;新窗口标题\x07
9.2 终端查询
| 命令 | 代码 | 说明 |
|---|---|---|
| 查询光标位置 | \x1b[6n |
终端返回\x1b[{row};{col}R |
9.3 鼠标跟踪
| 命令 | 代码 | 说明 |
|---|---|---|
| 启用鼠标跟踪 | \x1b[?1000h |
启用鼠标事件报告 |
| 禁用鼠标跟踪 | \x1b[?1000l |
禁用鼠标事件报告 |
10. 实现示例
10.1 ANSI转义码解析器框架
cpp
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAX_PARAMS 16
typedef struct {
int params[MAX_PARAMS];
int param_count;
char command;
} ansi_sequence_t;
int parse_ansi_sequence(const char *input, ansi_sequence_t *seq) {
if (!input || !seq || *input != '\x1b') {
return -1; // 不是转义序列
}
if (*(input + 1) != '[') {
return -1; // 不是CSI序列
}
// 重置参数
memset(seq->params, 0, sizeof(seq->params));
seq->param_count = 0;
const char *p = input + 2; // 跳过 "\x1b["
// 解析参数(可能多个,用;分隔)
while (isdigit(*p) || *p == ';') {
if (*p == ';') {
seq->param_count++;
p++;
continue;
}
int value = 0;
while (isdigit(*p)) {
value = value * 10 + (*p - '0');
p++;
}
seq->params[seq->param_count] = value;
seq->param_count++; // 先赋值,后计数
}
// 获取命令字符
seq->command = *p;
return (p - input) + 1; // 返回序列长度
}
10.2 简单颜色渲染示例
cpp
#include <stdio.h>
#include <string.h>
void color_print(const char *text, int fg_color, int bg_color) {
char cmd[32];
// 设置前景色
if (fg_color >= 0) {
sprintf(cmd, "\x1b[%dm", fg_color);
printf("%s", cmd);
}
// 设置背景色
if (bg_color >= 0) {
sprintf(cmd, "\x1b[%dm", bg_color);
printf("%s", cmd);
}
// 输出文本
printf("%s", text);
// 重置
printf("\x1b[0m");
}
int main() {
// 示例:各种颜色组合
color_print(" 红色文字 ", 31, -1);
color_print(" 黄色背景 ", -1, 43);
color_print(" 白字蓝底 ", 37, 44);
color_print(" 亮绿文字 ", 92, -1);
printf("\n");
// 使用高亮色
printf("\x1b[1m粗体文本\x1b[0m\n");
printf("\x1b[4m下划线文本\x1b[0m\n");
printf("\x1b[7m反转视频\x1b[0m\n");
return 0;
}
10.3 进度条动画示例
cpp
#include <stdio.h>
#include <unistd.h>
void draw_progress_bar(int percent, int width) {
int filled = width * percent / 100;
printf("\r[");
for (int i = 0; i < width; i++) {
if (i < filled) {
printf("\x1b[42m \x1b[0m"); // 完成的部分绿色
} else {
printf("\x1b[41m \x1b[0m"); // 未完成部分红色
}
}
printf("] %3d%%", percent);
fflush(stdout);
}
int main() {
for (int i = 0; i <= 100; i++) {
draw_progress_bar(i, 50);
usleep(50000); // 50ms
}
printf("\n完成!\n");
return 0;
}#include <stdio.h>
#include <unistd.h>
void draw_progress_bar(int percent, int width) {
int filled = width * percent / 100;
printf("\r[");
for (int i = 0; i < width; i++) {
if (i < filled) {
printf("\x1b[42m \x1b[0m"); // 完成的部分绿色
} else {
printf("\x1b[41m \x1b[0m"); // 未完成部分红色
}
}
printf("] %3d%%", percent);
fflush(stdout);
}
int main() {
for (int i = 0; i <= 100; i++) {
draw_progress_bar(i, 50);
usleep(50000); // 50ms
}
printf("\n完成!\n");
return 0;
}
10.4 光标控制示例
cpp
#include <stdio.h>
#include <unistd.h>
void gotoxy(int x, int y) {
printf("\x1b[%d;%dH", y, x);
}
void save_cursor() {
printf("\x1b[s");
}
void restore_cursor() {
printf("\x1b[u");
}
void clear_screen() {
printf("\x1b[2J");
}
int main() {
clear_screen();
// 在屏幕不同位置显示文本
gotoxy(10, 5);
printf("这是第5行第10列");
gotoxy(20, 10);
printf("这是第10行第20列");
gotoxy(1, 1);
printf("左上角");
// 保存光标位置
save_cursor();
gotoxy(30, 15);
printf("临时位置");
sleep(1);
// 恢复光标位置
restore_cursor();
printf(" (回到原位置)");
printf("\n\n按回车退出...");
getchar();
return 0;
}
11. 跨平台考虑
11.1 Windows支持
-
现代 Windows:Windows 10+ 支持ANSI序列,需要启用虚拟终端处理
-
旧版本:需要安装ANSICON等第三方工具
11.2 启用Windows控制台ANSI支持
cpp
#ifdef _WIN32
#include <windows.h>
void enable_ansi_support() {
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD dwMode = 0;
GetConsoleMode(hOut, &dwMode);
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
SetConsoleMode(hOut, dwMode);
}
#endif
11.3 检测终端类型
cpp
#include <stdlib.h>
int check_terminal_capabilities() {
const char *term = getenv("TERM");
if (!term) return 0;
// 检查终端类型
if (strstr(term, "xterm") || strstr(term, "screen") ||
strstr(term, "linux") || strstr(term, "tmux")) {
return 1; // 支持ANSI
}
return 0;
}
12. 安全性考虑
- 缓冲区溢出:解析转义序列时要确保缓冲区足够大
- 资源消耗:处理大量转义序列时注意性能
- 终端注入:清理用户输入,防止恶意转义序列注入
13. 调试技巧
调试 ANSI 序列时的一些实用方法:
- 查看原始输出 :
cat -v命令可以显示不可见字符 - 转义序列日志 :在程序开头添加
stty -echoctl禁用控制字符的^C显示 - 使用
script:script命令可以捕获终端会话,包括所有转义序列 - 测试命令 :
printf "\e[31m红色文本\e[0m\n"验证终端支持
14. 实用工具
| 工具 | 用途 | 命令示例 |
|---|---|---|
| tput | 终端能力查询 | tput colors 查看颜色支持 |
| infocmp | 终端描述 | infocmp $TERM 查看终端定义 |
| reset | 重置终端 | 终端异常时使用 reset |
通过掌握 ANSI 转义码,您可以创建跨平台、功能丰富的命令行应用程序,实现更好的用户体验和可视效果。