ANSI转义码详解

ANSI转义码是一种终端控制协议,通过在文本流中插入特殊的字符序列来控制终端的显示行为,包括文本颜色、光标移动、屏幕清除等高级功能。

1. 基础概念

1.1 组成结构

  • 转义字符 :通常使用 \x1b\033 表示
  • 控制序列引导符 :通常是 [
  • 参数字符 :用分号 ; 分隔的参数
  • 结束符:表示命令类型的字符

每个ANSI转义序列都以转义字符(ESC,ASCII 27)作为开始。 \033 是以 8进制 的形式代表着 10进制数27, 通过对照 ASCII表 不难找出,其为不可见 ASCII 字符ESC1B 位置,因为 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显示
  • 使用 scriptscript 命令可以捕获终端会话,包括所有转义序列
  • 测试命令printf "\e[31m红色文本\e[0m\n" 验证终端支持

14. 实用工具

工具 用途 命令示例
tput 终端能力查询 tput colors 查看颜色支持
infocmp 终端描述 infocmp $TERM 查看终端定义
reset 重置终端 终端异常时使用 reset

通过掌握 ANSI 转义码,您可以创建跨平台、功能丰富的命令行应用程序,实现更好的用户体验和可视效果。

相关推荐
计算机安禾2 小时前
【Linux从入门到精通】第21篇:Shell脚本开篇——什么是Shell?写第一个Hello World
linux·运维·服务器
Lumos_7772 小时前
Linux -- 系统调用
linux·运维·算法
南境十里·墨染春水2 小时前
C++笔记 STL——vector
开发语言·c++·笔记
坚持就完事了2 小时前
Linux中的cp命令
linux·运维·服务器
切糕师学AI2 小时前
使用 gdisk 快速判断硬盘分区表类型:是 GPT 还是 MBR?
linux·硬盘分区表·gdisk
2301_800976932 小时前
Linux的基本命令
linux·运维·服务器
故事和你913 小时前
洛谷-算法2-2-常见优化技巧3
开发语言·数据结构·c++·算法·深度优先·动态规划·图论
charlie1145141913 小时前
通用GUI编程技术——图形渲染实战(三十七)——D3D11初始化与SwapChain:从零搭建GPU渲染框架
开发语言·c++·3d·图形渲染
原来是猿3 小时前
线程安全的单例模式
linux·服务器·开发语言·单例模式·策略模式