如何合理的在 Windows 命令提示符中输出带颜色文本
引子
前几天使用 Linux 系统时,发现一些命令行工具的输出具有颜色。
带颜色的输出有一个优点,可以轻松的分辨信息的关键程度。
在 Windows 系统下,其实也可以在命令提示符中输出彩色文本。
实现方法
转义字符法
与 Linux 一样,Windows 系统下的 Windows Terminal 终端也可以识别转义字符
颜色表如下所示:
| 转义字符 | 颜色 |
|---|---|
| \033[01;30m | 黑色 |
| \033[01;31m | 红色 |
| \033[01;32m | 绿色 |
| \033[01;33m | 黄色 |
| \033[01;34m | 蓝色 |
| \033[01;35m | 紫色 |
| \033[01;36m | 青色 |
| \033[01;37m | 白色 |
| \033[01;40m | 背景黑色 |
| \033[01;41m | 背景红色 |
| \033[01;42m | 背景绿色 |
| \033[01;43m | 背景黄色 |
| \033[01;44m | 背景蓝色 |
| \033[01;45m | 背景紫色 |
| \033[01;46m | 背景青色 |
| \033[01;47m | 背景白色 |
| \033[00m | 清除颜色 |
这样做实际有一个弊端,对于传统的 cmd.exe 或 powershell.exe 来说,因为太过老旧,它们不识别这些转义字符。
所以这不算是一个好的方法,对于 Windows 系统,还得使用 Windows API。
Windows API 调用法
对于控制台的输出彩色文本操作,Microsoft 提供了一些 API。
主要是使用 SetConsoleTextAttribute() 函数控制输出文本的颜色
标程如下:
#include <iostream>
#include <Windows.h>
int main(){
::HANDLE handleOfConsole = ::GetStdHandle(STD_OUTPUT_HANDLE); // 获取控制台句柄,不理解的直接死记硬背
::SetConsoleTextAttribute(handleOfConsole, FOREGROUND_RED); // 设置输出为红色
std::cout << "Hello World" << std::endl; // 输出一个红色的 Hello World
::SetConsoleTextAttribute(handleOfConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY); // 恢复原状
return 0;
}
其中的 FOREGROUND_XXX 是 C++ 宏 如下表所示
| C++ 宏名称 | 颜色 |
|---|---|
| FOREGROUND_RED | 红色 |
| FOREGROUND_GREEN | 绿色 |
| FOREGROUND_BLUE | 蓝色 |
| FOREGROUND_INTENSITY | 高亮显示 |
| BACKGROUND_RED | 背景红色 |
| BACKGROUND_GREEN | 背景绿色 |
| BACKGROUND_BLUE | 背景蓝色 |
| BACKGROUND_INTENSITY | 背景高亮显示 |
就像美术课上教的那样,这些颜色可以混合。用 | 号混合
例如:
- FOREGROUND_GREEN | FOREGROUND_BLUE = 青色
- FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY = 浅青色
这样的方法可以稳定的在 Windows 系统的命令提示符中输出颜色文本,无论版本。
但是这样的代码不易读,所以可以封装一下
示例如下,我只封装了前景色中的红、绿、蓝和恢复原状,有兴趣的可以自行封装:
// TerminalColor.h
#include <iostream>
#include <Windows.h>
class TerminalColor {
public:
static std::ostream& Reset(std::ostream& os);
static std::ostream& Red(std::ostream& os);
static std::ostream& Green(std::ostream& os);
static std::ostream& Blue(std::ostream& os);
};
// TerminalColor.cpp
#include "TerminalColor.h"
::HANDLE handleOfConsole = ::GetStdHandle(STD_OUTPUT_HANDLE);
std::ostream& TerminalColor::Reset(std::ostream& os) {
::SetConsoleTextAttribute(handleOfConsole, 0x0008 | 0x0004 | 0x0002 | 0x0001);
return os;
}
std::ostream& TerminalColor::Red(std::ostream& os) {
::SetConsoleTextAttribute(handleOfConsole, 0x0008 | 0x0004);
return os;
}
std::ostream& TerminalColor::Green(std::ostream& os) {
::SetConsoleTextAttribute(handleOfConsole, 0x0008 | 0x0002);
return os;
}
std::ostream& TerminalColor::Blue(std::ostream& os) {
::SetConsoleTextAttribute(handleOfConsole, 0x0008 | 0x0001);
return os;
}
其中的十六进制数字是 C++ 宏展开后的结果
尾声
- 参考文档