C 语言中,识别 ANSI VT100 转义序列通常是通过处理字符串中的特殊字符来实现的。ANSI VT100 转义序列用于控制终端的显示效果,如颜色、光标移动等。它们通常以 \033(或者 \x1b)开头,后跟方括号和一些控制代码。

1、ANSI VT100 转义序列

ANSI 转义序列用于格式化控制台中的文本,例如改变文本颜色、定位光标或清除屏幕。现代系统的终端通常支持这些序列,但 Windows 命令提示符(CMD)和早期的控制台默认并不支持它们。Windows 控制台的限制, 历史上Windows 控制台(CMD)不支持 ANSI 转义序列。这是因为 Windows 控制台使用不同的系统来处理文本格式化和光标控制。然而,从 Windows 10(构建 10586 及之后版本)开始,Windows 原生支持 ANSI 转义序列,但可能需要通过编程启用它。

2、Windows 10 中启用 ANSI 转义序列

在 Windows 10(从构建 10586 起),可以通过使用 SetConsoleMode 函数来启用控制台对 ANSI 转义序列的支持。可以控制控制台是否解释 ANSI 转义序列。需要在标准输出(stdout)和标准错误(stderr)流上调用 SetConsoleMode。具体来说,需要启用 ENABLE_VIRTUAL_TERMINAL_PROCESSING 标志。

#include <windows.h>
#include <stdio.h>

int main() {
    // 获取标准输出的句柄
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    if (hConsole == INVALID_HANDLE_VALUE) {
        fprintf(stderr, "错误: 无法获取控制台句柄\n");
        return 1;
    }

    // 获取当前控制台模式
    DWORD dwMode;
    if (!GetConsoleMode(hConsole, &dwMode)) {
        fprintf(stderr, "错误: 无法获取控制台模式\n");
        return 1;
    }

    // 启用 ANSI 转义序列处理
    dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
    if (!SetConsoleMode(hConsole, dwMode)) {
        fprintf(stderr, "错误: 无法设置控制台模式\n");
        return 1;
    }

    // 现在可以使用 ANSI 转义序列
    printf("\x1b[31m这是一段红色文本\x1b[0m\n");

    return 0;
}

3、旧版本的 Windows(Windows 10 之前)

对于早于 Windows 10 的版本,或者如果控制台不原生支持 ANSI 转义序列,可以使用外部库,或者使用 Windows 控制台 API 调用。

1)使用外部库

可以使用像 ANSI.SYS 这样的外部库,或者使用第三方库(如 PDCurses)来让 Windows 控制台支持 ANSI 转义序列。

#include <stdio.h>
#include <stdlib.h>

int main() {
    // 检查是否支持 ANSI 转义序列
    // 这通常需要外部库,如 ANSICON,在 Windows 10 之前的版本中
    printf("\x1b[31mThis text is red!\x1b[0m\n");  // 红色文字
    printf("\x1b[32mThis text is green!\x1b[0m\n"); // 绿色文字
    printf("\x1b[33mThis text is yellow!\x1b[0m\n"); // 黄色文字
    printf("\x1b[1mThis is bold text!\x1b[0m\n"); // 粗体文字
    return 0;
}

2)使用 Windows 控制台 API 调用

可以通过使用 Windows 控制台 API(例如 SetConsoleTextAttributeSetConsoleCursorPosition)来实现类似的效果,例如改变颜色和定位光标。虽然这比 ANSI 转义序列的功能少,但这些 API 调用可以用来控制控制台。

#include <windows.h>
#include <stdio.h>

void enable_virtual_terminal_processing() {
    // 获取当前控制台的输出句柄
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    if (hConsole == INVALID_HANDLE_VALUE) {
        printf("无法获取标准输出句柄.\n");
        return;
    }

    // 获取当前控制台模式
    DWORD dwMode;
    if (!GetConsoleMode(hConsole, &dwMode)) {
        printf("无法获取控制台模式.\n");
        return;
    }

    // 启用虚拟终端处理
    dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;

    // 设置新的控制台模式
    if (!SetConsoleMode(hConsole, dwMode)) {
        printf("无法设置控制台模式.\n");
        return;
    }
}

void print_colored_text() {
    // 启用虚拟终端处理,支持 ANSI 转义序列
    enable_virtual_terminal_processing();

    // 打印红色文本(使用 ANSI 转义序列)
    printf("\033[31m这是红色文本\033[0m\n");

    // 打印绿色文本
    printf("\033[32m这是绿色文本\033[0m\n");

    // 打印背景为蓝色的文本
    printf("\033[44m背景是蓝色的文本\033[0m\n");
}

int main() {
    print_colored_text();
    return 0;
}

4、跨平台方法

如正在编写跨平台程序,并且需要在类 Unix 系统和 Windows 系统上都能工作,可以检测操作系统,并有条件地启用必要的转义序列处理。

#include <stdio.h>

#ifdef _WIN32
#include <windows.h>

// 在 Windows 上启用 ANSI 转义序列
void enable_virtual_terminal_processing() {
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    if (hConsole == INVALID_HANDLE_VALUE) {
        printf("无法获取标准输出句柄.\n");
        return;
    }

    DWORD dwMode;
    if (!GetConsoleMode(hConsole, &dwMode)) {
        printf("无法获取控制台模式.\n");
        return;
    }

    // 启用虚拟终端处理
    dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;

    if (!SetConsoleMode(hConsole, dwMode)) {
        printf("无法设置控制台模式.\n");
        return;
    }
}

void print_colored_text() {
    // 启用虚拟终端处理
    enable_virtual_terminal_processing();

    // 打印红色文本
    printf("\033[31m这是一段红色文本\033[0m\n");
}

#else
// 对于类 Unix 系统,ANSI 转义序列原生支持
void print_colored_text() {
    // 打印红色文本
    printf("\x1b[31m这是一段红色文本\x1b[0m\n");
}

#endif

int main() {
    // 打印带颜色的文本
    print_colored_text();
    return 0;
}