本文用 Rust 语言实现一个简单的进度条功能,并介绍通过转义码在终端打印带颜色等格式的字符串。
一、代码实现
先上代码。
1 | pub fn bar_show() -> Result<(), Box<dyn Error>> { |
因为终端输出的进度条是带颜色的,在这里没法显示,只能通过截图看。
二、代码解释
进度条前面的指示字符是 "-\\|/"
交替显示,呈现出动态效果,因为 \
需要转义,所以是两个反斜杠 \\
。
然后就是进度条从 0-100 开始,每一次循环输出指示字符(模 4),空白字符重复 (index / times) 次,根据进度条长度进行调整除数。然后刷新输出流,要不然输出会在缓存中,每隔一段时间才会输出到设备,不会实时显示进度条进度,最后再睡眠 30ms,让进度条缓慢加载。
最重要的是这一句:"\r{} \u{1b}[42m{}\u{1b}[0m [ {}% ]"
。
首先,\r
表示将光标置于本行行首,使用 print!
可以使得每次输出覆盖之前输出的行。然后 \u
表示输出后面的 UniCode
字符,{}
就不用说了,是 Rust 里用来控制格式化输出的。
注:Unix 系统里,每行结尾只有“<换行>”,即“\n”;Windows 系统里面,每行结尾是“<换行><回车 >”,即“\n\r”;Mac 系统里,每行结尾是“<回车>”。一个直接后果是,Unix/Mac 系统下的文件在 Windows里打开的话,所有文字会变成一行;而 Windows 里的文件在 Unix/Mac 下打开的话,在每行的结尾可能会多出一个 ^M 符号。所以,如果你需要跨平台处理文本文件,可能会被回车换行搅得有点头大。
0x0D(ascii 码是 13) 指的是“回车” \r 是把光标置于本行行首
0x0A(ascii 码是 10) 指的是“换行” \n 是把光标置于下一行的同一列
0x0D + 0x0A 回车换行 \r\n 是把光标置于下一行行首
\u{1b}[42m
这句的格式是 \x1b[<代码>;<代码>
,其中 \x1b[
是十六进制 1b,写成八进制 \033
也行,然后一个左中括号,是特殊的终端控制符,格式固定。然后后面跟上一个数字和一个字母,这里 42m
就是将背景设置为绿色,字母 m 表示设置的属性类别,数字代表属性值。
下面是一些其他属性,可以设置文本的颜色,背景色,设置是否加粗,下划线等。
1 | \033[0m 关闭所有属性 |
各个数字代表的颜色如下。
1 | 字背景颜色范围:40--49 |
另外,同类的多种设置项可以组合在一起,中间用分号 ;
隔开。
例如 print!("\u{1b}[31;1;3;4m{}\u{1b}[0m", "Rosa");
,其中 \u{1b}[31;1;3;4m
中,31
表示前景色(字的颜色)是红色,1
表示加粗,3
表示设置斜体,4
表示设置下划线。则上述代码输出的是一个红色加粗加下划线的斜体字符串 Rosa
。最后的 \u{1b}[0m
表示将格式清除掉,否则下面输出的任何字符都将使用刚刚的样式。
同样,在 C 语言中也可以实现。
1 | int color = 32; |
这行命令首先 \033[20;1H
将光标移动到终端第 20 行第 1 列,之后的 \033[1;4;32m
将文本属性设置为高亮、带下划线且颜色为绿色,然后输出 Hello,world
,最后 \033[0m
将终端属性恢复为默认值。
三、一些参考实现
3.1 bash 中输出带样式的字符
在 bash 中,通常我们可以使用 echo
命令加 -e
选项输出各种颜色的文本,echo -e
表示处理特殊字符,开启转义。
1 | echo -e "\033[31mRed Text\033[0m" |
3.2 C 语言中输出颜色表
1 |
|
四、参考文档
浅析 \x1B[1;3;31mxterm.js\x1B[0m
是什么?如何在终端输出带颜色等格式的字符串
Rust 官方有进度条实现的 indicatif crate,用法比较全面,这里是 源码解析