如何在C和C++中使用ANSI Escape Codes输出彩色文本?

11

我了解了 ANSI-C 转义码 这里 的相关信息。尝试在 C/C++ 的 printf/std::cout 中使用它来给输出到控制台的文本上色,但是没有成功。

我的尝试:

#include <iostream>
#include <cstdio>

int main() {
    int a=3, b=5;
    int &ref = a;
    ref = b;
    
    //cout << "\155\32\m" << a << b <<'\n'; //here it prints m→m 5, no colored text
    printf("\155\32\m %d",a); //here to it prints same - m→m 5, 

    getchar();
}

我该如何使用这些转义码将彩色文本输出到控制台?

我有什么遗漏的吗?

另外,我记得在一些C++代码中看到过对这个函数的调用。

textcolor(10);

但是在g++和Visual Studio中都会出现编译错误。哪个编译器有这个函数可用?有任何细节吗?

10个回答

12

恐怕您忘记了 ESC 字符:

#include <cstdio>

int main()
{
    printf("%c[%dmHELLO!\n", 0x1B, 32);
}

很不幸,这只能在支持ANSI转义序列的控制台上运行(比如使用bash的Linux控制台,或者使用ansi.sys的旧版Windows控制台)。


2
@pau.estella - 谢谢,但它仍然没有打印颜色。相反,它打印了←[32mHELLO!另外,您能解释一下这个printf("%c[%dmHELLO!\n", 0x1B, 32);是如何工作的吗? - goldenmean
1
@ goldenmean 如果这个答案对您无效,也许您应该接受其他答案。 - VLL
或者,您可以使用 \xNN 表示法为字符串定义 ESC 的字符代码,其中 NN 是符号的十六进制代码(0x1B == 27 十进制)。此外,您还可以将字符串分成几个部分以使代码更清晰(请注意,编译器会将字符串字面量 "..." 合并在一起):`printf ("\x1B" "[%dm" "HELLO!\n", 32);`另请参见 @Baltasarq 的回答和下面的评论。 - ded32
实际上,Windows 10及以上版本的应用程序现在也提供了同样的功能。我认为你需要启用它,但不仅仅是ANSI VT100类似的文本输出回来了,而且几乎整个控制台API都已经过时了。 - TJ Bandrowsky

8
我曾经创建了一个非常 简单的文本管理库,它是跨平台的,对于Windows使用本地API调用,对于其他平台使用ANSI转义序列。它有完整的文档,你也可以浏览源代码。
关于你的具体问题,我认为你缺少一些代码。例如,如果想要改变文本的颜色,应该使用类似如下的内容:
static const char * CSI = "\33[";
printf( "%s%s", CSI, "31m" );   // RED

希望这有所帮助。

感谢提供的信息。但我猜 ANSI 转义序列只能在 DOS 控制台上用于为文本着色。在 Windows 中的命令提示符中,它会打印出一些控制字符而不是彩色文本。 - goldenmean
@ goldenmean,是的,对于Windows命令控制台,您必须使用Windows API调用。我向您指出的库可以自动化此过程。 - Baltasarq
1
我几乎想建议在这种情况下使用预处理器宏,这样你就可以将你的字符串写成 printf("Hello" COLOR_RED " World" COLOR_OFF); - Kerrek SB

6

在 Windows 10 中,可以通过在当前控制台激活 VT100 模式来使用 VT100 样式:

#include <windows.h>
#include <iostream>

#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
#define DISABLE_NEWLINE_AUTO_RETURN  0x0008

int main()
{       
   HANDLE handleOut = GetStdHandle(STD_OUTPUT_HANDLE);
   DWORD consoleMode;
   GetConsoleMode( handleOut , &consoleMode);
   consoleMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
   consoleMode |= DISABLE_NEWLINE_AUTO_RETURN;            
   SetConsoleMode( handleOut , consoleMode );

   for (int i = 0; i < 10; ++i)
   {
      std::cout << "\x1b[38;2;" << 5 * i << ";" << 255 - 10 * i << ";220m" 
             << "ANSI Escape Sequence " << i << std::endl;
   }
}

请查看 MSDN 网页: [https://learn.microsoft.com/zh-cn/windows/console/console-virtual-terminal-sequences][1]


5

提醒各位读者: https://en.wikipedia.org/wiki/ANSI_escape_code#DOS_and_Windows

在2016年,微软发布了Windows 10 Version 1511更新,意外地实现了对ANSI转义序列的支持。这个变化旨在补充为Linux子系统提供支持的Windows控制台宿主程序,为类Unix系统中基于终端的软件添加了字符转义码的支持。这不是默认行为,必须通过Win32 API编程方式启用,使用SetConsoleMode(handle, ENABLE_VIRTUAL_TERMINAL_PROCESSING)


理想情况下,您应该编写一个完整的答案。这更像是一条评论而不是答案帖子。 - starball

3

在DOS系统中,ANSI转义码可以通过ansi.sys设备驱动程序工作。但是在Windows XP或更高版本中无法使用它们。您需要使用控制台API的SetConsoleTextAttribute()函数。

textcolor函数可用于Borland Turbo C++编译器。


2

Windows 10支持256种颜色扩展的VT100和派生终端仿真技术上的ANSI Escape Sequences。有关详细说明和示例,请参见控制台虚拟终端序列页面。

std::ostringstream ss;
for (int i = 0; i < 10; ++i)
    ss << "\x1b[38;2;" << 5 * i << ";" << 255 - 10 * i << ";220m" 
        << "ANSI Escape Sequence " << i << std::endl;   
std::cout << ss.str();

1

正如我在答案中所说,只要用户运行的是Windows 10的Threshold 2版本,Windows现在支持ANSI代码。 - Shades
105xx版本是唯一默认启用VT100序列的版本。在之前和之后的版本中,它默认禁用了,因为它被错误地启用了。在这里查看解释 wpdev.uservoice.com/forums/… - JMS
最新的Windows 10中,你可以通过以下reghack在conhost中启用ANSI — 在HKCU\Console中创建一个名为VirtualTerminalLevel的DWORD,并将其设置为0x1;然后重新启动cmd.exe。 — 你可以使用以下PowerShell进行测试:"[char]27;?[1;31mele [char]27;?[32mct [char]27;?[33mroni [char]27;?[35mX [char]27;?[36mtar[char]27;[m". - JMS
它始终处于启用状态,@JMS在第一条评论中所写的不是真的,它并不是因为错误而被启用的。它是为了让使用ANSI格式代码的应用程序在命令行窗口中正确地工作而启用的,当然也是为了更轻松地通过颜色对某些单词进行分类。 - user7090116
@BosnianCoder 你说得对,我在2018年的评论已经过时了。Windows Terminal是在2019年推出的,它默认支持ANSI序列。请参见**Windows和Dos**。 - JMS

0

颜色化 ANSI 转义码使用 选择图形呈现 (SGR) 序列,其格式为 CSI n m,其中 CSI(代表控制序列引导符)序列只是转义字符后跟一个开方括号,n 是某个参数,而 m 是字面上的 "m" 字符。

麻烦的部分实际上只是在C++字符串字面值中获取转义字符。您可以查看https://en.cppreference.com/w/cpp/language/escape了解有关C++中字符串转义的信息。简而言之,您可以使用八进制形式,例如\nnn,或十六进制形式,例如\xn...ASCII中的ESC字符的值为27,在八进制中为33,在十六进制中为1b。因此,您可以使用"\033[...m""\x1b[...m"

例如:

"\033[31mred \033[33myellow \033[32mgreen \033[36mcyan \033[34mblue \033[35mmagenta"
"\x1b[31mred \x1b[33myellow \x1b[32mgreen \x1b[36mcyan \x1b[34mblue \x1b[35mmagenta"

(趣闻:Bash 使用类似的字符串转义序列,因此您可以在 Bash shell 中使用 echo -e 命令输出上述字符串文字,它也会起作用)
对于 C++20,在我的一个项目的头文件中,我使用以下代码片段来定义一些更易读的常量:
#include <string_view>

struct SgrPair final {
    std::string_view on;
    std::string_view off;
};
#if USE_ANSI_ESC
#define SGR(NAME, ON_STR, OFF_STR) inline constexpr SgrPair NAME { .on {(ON_STR)}, .off {(OFF_STR)} };
#else
#define SGR(NAME, ON_STR, OFF_STR) inline constexpr SgrPair NAME { .on {""}, .off {""} };
#endif

SGR(dim, "\033[2m",  "\033[22m")
SGR(red, "\033[31m", "\033[39m")

#undef SGR

在上面的代码片段中,进行编译的用户可以选择是否将USE_ANSI_ESC宏定义为真值。
另请参见 ANSI颜色转义序列列表 https://www.ecma-international.org/publications-and-standards/standards/ecma-48/

Windows痛苦和折磨有趣

如果您的程序在类似cmd的Windows控制台上打印,则需要在程序中编写一些内容以在该控制台中启用ANSI转义代码(请参见 https://learn.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences):

#ifdef _WIN32
#include <windows.h>
#endif

int main() {
    // ...
    #ifdef _WIN32
    DWORD con_mode;
    GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), &con_mode);
    con_mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
    SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), con_mode);
    // ...
}

其他答案已经提到了这一点,但我添加了一些预处理包装,使其更容易在非Windows平台上编译而无需更改代码。
"Textcolor"是Turbo C/C++编译器的一个函数。请参见Turbo C/C++ Compiler 2.0文档第384页。另请参见:conio.h不包含textcolor()吗?

0

这将在任何支持ANSI转义序列的操作系统中运行

#include <iostream>
    
void printColored(char r, char g, char b, char _char_) {
  std::cout << '\33' << '[' << '38' << ';' << '2' << ';' << r << ';' << g << ';' << b << 'm' << _char_ << '\33' << '[' << 'm'
}

注意:
char r 是 RGB 中的红色
char g 是 RGB 中的绿色
char b 是 RGB 中的蓝色
char char 是要打印彩色文本的字符
关于使用 ANSI Escape 输出 RGB 彩色文本,可能已经有人回答过了,可以参考 ANSI Color Specific RGB Sequence Bash 如果您认为这不正确,请编辑它,我会接受修改。

-1
我之前也遇到过这个问题,在Windows 10上使用GCC。我不得不设置以下注册表键才能使其正常工作。[HKEY_CURRENT_USER\Console] "VirtualTerminalLevel"=dword:00000001

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接