前言
上一次涛之雨大佬已经在这篇文章中讲解了彩色字符的打印方法:ANSI转义码[维基(内容已经多了一点了)]但事实上,ANSI转义码的用处不止于此。
ANSI转义码还能做什么
ANSI转义码还能够修改文本样式,控制光标位置。比如,下面这张表列出了一些常用的并且最新版Windows终端支持的用于控制光标的ANSI转义码:(此表摘自前文给出的链接)
代码 |
名称 |
作用 |
CSI n A |
CUU – 光标上移(Cursor Up) |
光标向指定的方向移动n (默认1)格。如果光标已在屏幕边缘,则无效。 |
CSI n B |
CUD – 光标下移(Cursor Down) |
同上 |
CSI n C |
CUF – 光标前移(Cursor Forward) |
同上 |
CSI n D |
CUB – 光标后移(Cursor Back) |
同上 |
CSI n E |
CNL – 光标移到下一行(Cursor Next Line) |
光标移动到下面第n (默认1)行的开头。 |
CSI n F |
CPL – 光标移到上一行(Cursor Previous Line) |
光标移动到上面第n (默认1)行的开头。 |
CSI n G |
CHA – 光标水平绝对(Cursor Horizontal Absolute) |
光标移动到第n (默认1)列。 |
CSI n;m H |
CUP – 光标位置(Cursor Position) |
光标移动到第n 行、第m 列。值从1开始,且默认为1 (左上角)。例如CSI ;5H 和CSI 1;5H 含义相同;CSI 17;H 、CSI 17H 和CSI 17;1H 三者含义相同。 |
CSI n J |
ED – 擦除显示(Erase in Display) |
清除屏幕的部分区域。如果n 是0(或缺失),则清除从光标位置到屏幕末尾的部分。如果n 是1,则清除从光标位置到屏幕开头的部分。如果n 是2,则清除整个屏幕。如果n 是3,则清除整个屏幕,并删除回滚缓存区中的所有行。 |
CSI n K |
EL – 擦除行(Erase in Line) |
清除行内的部分区域。如果n 是0(或缺失),清除从光标位置到该行末尾的部分。如果n 是1,清除从光标位置到该行开头的部分。如果n 是2,清除整行。光标位置不变。 |
CSI n S |
SU – 向上滚动(Scroll Up) |
整页向上滚动n (默认1)行。新行添加到底部。 |
CSI n T |
SD – 向下滚动(Scroll Down) |
整页向下滚动n (默认1)行。新行添加到顶部。 |
还有一些转义码用于控制字体样式:
代码 |
作用 |
备注 |
0 |
重置/正常 |
关闭所有属性。 |
1 |
粗体/增加强度/高亮 |
2 |
弱化(降低强度) |
3 |
斜体 |
4 |
下划线 |
5 |
闪烁 |
7 |
反显 |
前景色与背景色交换。 |
8 |
隐藏 |
9 |
划除 |
加上删除线。 |
22 |
正常颜色或强度 |
不强不弱。 |
23 |
非斜体 |
24 |
关闭下划线 |
25 |
关闭闪烁 |
27 |
关闭反显 |
28 |
关闭隐藏 |
29 |
关闭划除 |
通过这些转义字符,我们可以制作一个极富艺术性(bushi)的批处理。
批处理中的小技术
要制作这样的批处理,首先要生成ESC 字符。可以使用以下代码:
for /f %%a in ('echo prompt $E ^| cmd') do set ESC=%%a
然后在代码中可以使用%ESC% 表示ESC 字符。
批处理中还需要生成随机数,我使用了类似以下的命令:
set /a randout=%random%*随机数的最大值/32767
为什么这样写而不是直接取%random% 的余数呢?因为直接取余得到不同数的概率不相等,这与C/C++中直接rand()%n 存在的问题是一样的。
另外,为了调用方便,适当使用函数/子程序也能提高编程效率。怎么写子程序?很简单:
echo 调用子程序:
call :name
REM 主程序到此结束,批处理退出:
exit /B
REM 下面是子程序部分
:name
REM name是一个标签,可以标注代码中的跳转点,
REM 也相当于子程序的起点,你可以把它换成你要的名字
echo Hello!
exit /B
REM 上一行指令相当于return,批处理没有子程序结束标记,
REM 必须用exit /B退回主程序。
程序中还使用set /p 显示提示信息不换行的特性实现了文本输出不换行:
<nul set /p _dev_stdout=输出文本
批处理源码
注意:多数文本编辑器默认以UTF-8编码保存文件,请在保存批处理时将其以ANSI编码保存!!!
终端的上半部分随机填充方块是使用光标位置控制序列实现的,最底下的一行文本是使用字体样式控制序列实现的。
@echo off
REM 生成ESC字符
for /f %%a in ('echo prompt $E ^| cmd') do set ESC=%%a
set cnt=100
:main
set out=%ESC%[
call :randposY
set out=%out%%randout%;
call :randposX
set out=%out%%randout%H%ESC%[48;2;
call :randcolor
set out=%out%%randout%;
call :randcolor
set out=%out%%randout%;
call :randcolor
set out=%out%%randout%m %ESC%[0m
<nul set /p _dev_stdout=%out%
REM 每循环10次显示一次新的底部文本
REM 不加判断文本刷新太快,效果很差
set /a cnt=cnt+1
if %cnt% lss 10 (goto main)
call :randstyle
set out=%ESC%[30;1H%ESC%[%randout%m%ESC%[38;2;
call :randcolor
set out=%out%%randout%;
call :randcolor
set out=%out%%randout%;
call :randcolor
set out=%out%%randout%m%ESC%[48;2;
call :randcolor
set out=%out%%randout%;
call :randcolor
set out=%out%%randout%;
call :randcolor
set out=%out%%randout%m批处理精神污染
call :randstyle
set out=%out%%ESC%[%randout%m%ESC%[38;2;
call :randcolor
set out=%out%%randout%;
call :randcolor
set out=%out%%randout%;
call :randcolor
set out=%out%%randout%m%ESC%[48;2;
call :randcolor
set out=%out%%randout%;
call :randcolor
set out=%out%%randout%;
call :randcolor
set out=%out%%randout%mBy 吾爱破解论坛 luliucheng%ESC%[0m
<nul set /p _dev_stdout=%out%
set cnt=0
goto main
REM 各种子程序
:randposX
set /a randout=%random%*60/32767*2
exit /B
:randposY
set /a randout=%random%*30/32767
exit /B
:randcolor
set /a randout=%random%/128
exit /B
:randstyle
set randsource=123479
set /a randout=%random%*6/32767
setlocal ENABLEDELAYEDEXPANSION
set randout=!randsource:~%randout%,1!
endlocal
exit /B
|