关于转义序列
问题引入
首先有这样一个有趣的问题
// escape.c
;
;
这两行代码分别应该输出什么呢?看到这道题的时候,我是懵逼的,因为\r \b这样的字符实在是很少使用。于是,我上机测试了一下。
### Environment: Windows 10 20H2, gcc, powershell ###
f gdfrge
f gdfrge
### Environment: Ubuntu 20.04, gcc, zsh ###
看到输出结果,我:???
这个输出主要有几个问题不好解释:
- 为什么不同环境下输出的结果不同?
- Ubuntu环境下,为什么第二条语句的输出没有后5个字符?
- 将字符串分为两个部分,\r 之前和 \r 之后。按照dfrge的位置来计算,前一部分中的 \t 的宽度为2个字符,后一部分中 \t 的宽度为7个字符,\t 的宽度是如何计算的?
转义序列
我们先来回顾一下书上所描述的一些转义序列:
| Escape Sequences | Meaning |
|---|---|
| \b | Backspace. |
| \n | Newline. |
| \r | Carriage return. |
| \t | Horizontal tab. |
| \v | Vertical tab. |
| \a | Alert (ANSI C). |
| \f | Form feed. |
我们分别来看一下这些转义序列:
\b 用来将光标向回移动一格,但是要注意的是,这里的移动光标并不等于我们敲击键盘上的退格键(Backspace),\b仅仅会移动光标,而回退的内容并不会被删除掉,接下来的内容会插入到光标后面,覆盖掉原有的内容。另外,在stdin中的输入也会覆盖光标后的字符。
;
;
;
;
----------------------------------------
Output:
Hi there, welcome!
//输入John
Please type your name: John.
\n \r 之所以将这两个字符放在一起,是因为在不同的系统中处理文件中“换行”的方式不同,因此这两个字符的含义没有一个统一标准。Windows使用Carrier Return(\r)来表示将光标置于行开头,用Line Feed(\n)来将光标移动到当前位置的正下方一行;Linux则直接使用(\n)来表示回车+换行。如果你想了解为什么有这样的区别,Stack Overflow联合创始人Jeff Atwood写的这篇文章十分清晰的阐释了这个问题。
不过对于命令行来说,似乎并没有这样的区别(具体原因未知,有待进一步测试)。
\t 用来将光标移动到下一个制表位(Tab stop)。假设你现有环境中制表符的宽度是w(在终端中,一般w = 8),光标所处位置是p,那么输出一个\t会将光标移动到第 n*w 位,其中n为一个整数,且 n*w >= p
; ;
;
----------------------------------------
Output:
bbbbb bbbbbbbb
\v 垂直制表符,基本上等同于 \n \t 一同作用的效果。据说出现的目的是为了加快打印机的打印速度(?)
\a 播放警示声音,这个控制符蛮有意思的,可以用来提示用户
\f 用来告诉打印机强制跳转到下一页,不过在现代系统中好像并没有这样的功能
问题解释
1. 为什么不同环境下输出的结果不同?
本质上讲,转义序列只是一些字符,C只能将这些字符传入输出流中,至于如何处理,因流和系统环境的差异而有很多不同。
例如,上面的代码在Windows下运行,得到的结果并没有?ab?c,说明Windows处理 “??ab?c\t?dfrge\rf**\t**g\n” 中标重点的 \t 时,会选择用 \t 覆盖掉已经输出了的内容,即 ?ab?c。相反,在Ubuntu中并不会出现这样的现象,因为Ubuntu中的 \t 并不会覆盖已经输出的内容,而仅仅是将光标移动到下一个Tab stop。
2. Ubuntu环境下,为什么第二条语句的输出没有后5个字符?
Linux terminal似乎只会打印到所在行光标所在位置,对于光标后面的字符并不会打印。在Ubuntu上测试另外一个字符串:
;
----------------------------------------
Output:
f?ab?c gdfrge
这一方面说明在Ubuntu上 \t 不会覆盖已经输出的字符,一方面说明终端只会输出光标之前的内容。
3. \t的宽度是如何计算的 ?
参考上一部分中关于制表位的描述。
ANSI转义序列
刚才还留下了一个问题,\f 并不能实现强制换页。那么如果想实现强制换页的操作,应该怎么办呢?
**ANSI转义序列(ANSI escape sequences)**是一种带内信号的转义序列标准,用于控制视频文本终端上的光标位置、颜色和其他选项。在文本中嵌入确定的字节序列,大部分以 ESC 转义字符和“[“字符开始,终端会把这些字节序列解释为相应的指令,而不是普通的字符编码。
ANSI转义序列能够实现更多功能,包括控制光标向上移动、控制输出字符的颜色、清屏等等。这里是一份完整的查询表,下面的例子中用到了一些常用的功能。
//Environment: Ubuntu 20.04, gcc, zsh
//Not sure about whether this will work on windows.
//Windows 10 and windows terminal support ANSI escape sequence
//so if you are using them, this should work properly.
int
’\033’在ASCII编码中是转义字符的意思,它标志着后面的东西的意思发生了变化。
Try Yourself
用转义字符实现进度条
这里写了一个简单的打印进度条的函数,通过循环调用来实现进度条的效果。
void
int
跳舞的颜文字
int