OEM Alt码在处理1-31和127这个范围内的字符时存在误导。系统的OEM代码页是ASCII字符集的超集。但是,Alt码并不代表ASCII控制字符,而是旧版IBM PC系统中有时会显示和打印ASCII控制字符的字符。例如,按下Alt+1会输入"☺"(U+263A,白色微笑脸),而不是ASCII SOH(U+0001,标题开始)。更糟糕的是,当使用WideCharToMultiByte
将这些字符编码为OEM代码页时,默认的行为是使用相应的ASCII控制字符作为最佳匹配编码。因此,文本编辑器可能不会警告您所看到的内容与实际得到的不同。
控制台不会像旧版IBM PC图形字符一样显示控制字符。它会解释其中的一些字符,如U+0009(水平制表符——将光标向前移动8个空格)和U+000D(回车——将光标移动到下一行的开头),但大多数情况下它们会以当前字体的未映射字符的字形显示,例如一个带问号的方框或一个空盒子。如果要在控制台上打印"☺",则应使用控制台的宽字符API,该API适用于Windows本机Unicode(UTF-16LE)字符串。
幸运的是,CMD是一个Unicode应用程序,因此在控制台上打印"☺"不会有问题。问题在于要使用哪种编码来保存批处理脚本。唯一的通用解决方案是将批处理文件保存为UTF-8无BOM格式。您需要一个能够保存UTF-8无BOM格式的IDE或文本编辑器,例如Notepad++。
CMD使用遗留控制台代码页逐行解码批处理脚本,您可以使用chcp.com 65001
命令将其更改为UTF-8。我建议不要永久更改为UTF-8,因为根据Windows版本,控制台在使用代码页65001时存在各种错误。您可以暂时切换到UTF-8以加载非ASCII字符串作为环境变量。否则,请将批处理文件的其余部分严格保持为7位ASCII,以避免本地化问题。
下面是一个示例。可能有比创建所有这些本地环境变量更通用的方法,但这只是为了证明它原则上可行。
graphics_ctl.bat
@echo off
REM ASCII Control-Character Graphics
REM File encoding: UTF-8 (no BOM)
REM Set the console to codepage 65001 (UTF-8).
for /f "tokens=2 delims=:" %%a in ('chcp.com') do set "CONSOLE_CODEPAGE=%%a"
set "CONSOLE_CODEPAGE=%CONSOLE_CODEPAGE: =%"
chcp.com 65001 >NUL
set "GCTL_WHITE_SMILING_FACE=☺"
set "GCTL_BLACK_SMILING_FACE=☻"
set "GCTL_BLACK_HEART_SUIT=♥"
set "GCTL_BLACK_DIAMOND_SUIT=♦"
set "GCTL_BLACK_CLUB_SUIT=♣"
set "GCTL_BLACK_SPADE_SUIT=♠"
set "GCTL_BULLET=•"
set "GCTL_INVERSE_BULLET=◘"
set "GCTL_WHITE_CIRCLE=○"
set "GCTL_INVERSE_WHITE_CIRCLE=◙"
set "GCTL_MALE_SIGN=♂"
set "GCTL_FEMALE_SIGN=♀"
set "GCTL_EIGHTH_NOTE=♪"
set "GCTL_BEAMED_EIGHTH_NOTES=♫"
set "GCTL_WHITE_SUN_WITH_RAYS=☼"
set "GCTL_BLACK_RIGHT_POINTER=►"
set "GCTL_BLACK_LEFT_POINTER=◄"
set "GCTL_UP_DOWN_ARROW=↕"
set "GCTL_DOUBLE_EXCLAMATION_MARK=‼"
set "GCTL_PILCROW_SIGN=¶"
set "GCTL_SECTION_SIGN=§"
set "GCTL_BLACK_RECTANGLE=▬"
set "GCTL_UP_DOWN_ARROW_WITH_BASE=↨"
set "GCTL_UP_ARROW=↑"
set "GCTL_DOWN_ARROW=↓"
set "GCTL_RIGHT_ARROW=→"
set "GCTL_LEFT_ARROW=←"
set "GCTL_RIGHT_ANGLE=∟"
set "GCTL_LEFT_RIGHT_ARROW=↔"
set "GCTL_BLACK_UP_TRIANGLE=▲"
set "GCTL_BLACK_DOWN_TRIANGLE=▼"
set "GCTL_HOUSE=⌂"
REM Restore the previous console codepage.
chcp.com %CONSOLE_CODEPAGE% >NUL
graphics_box.bat
@echo off
REM Box-Drawing Graphics
REM File encoding: UTF-8 (no BOM)
REM Set the console to codepage 65001 (UTF-8).
for /f "tokens=2 delims=:" %%a in ('chcp.com') do set "CONSOLE_CODEPAGE=%%a"
set "CONSOLE_CODEPAGE=%CONSOLE_CODEPAGE: =%"
chcp.com 65001 >NUL
set "GBOX_LIGHT_SHADE=░"
set "GBOX_MEDIUM_SHADE=▒"
set "GBOX_DARK_SHADE=▓"
set "GBOX_LIGHT_VERTICAL=│"
set "GBOX_LIGHT_VERTICAL_AND_LEFT=┤"
set "GBOX_VERTICAL_SINGLE_AND_LEFT_DOUBLE=╡"
set "GBOX_VERTICAL_DOUBLE_AND_LEFT_SINGLE=╢"
set "GBOX_DOWN_DOUBLE_AND_LEFT_SINGLE=╖"
set "GBOX_DOWN_SINGLE_AND_LEFT_DOUBLE=╕"
set "GBOX_DOUBLE_VERTICAL_AND_LEFT=╣"
set "GBOX_DOUBLE_VERTICAL=║"
set "GBOX_DOUBLE_DOWN_AND_LEFT=╗"
set "GBOX_DOUBLE_UP_AND_LEFT=╝"
set "GBOX_UP_DOUBLE_AND_LEFT_SINGLE=╜"
set "GBOX_UP_SINGLE_AND_LEFT_DOUBLE=╛"
set "GBOX_LIGHT_DOWN_AND_LEFT=┐"
set "GBOX_LIGHT_UP_AND_RIGHT=└"
set "GBOX_LIGHT_UP_AND_HORIZONTAL=┴"
set "GBOX_LIGHT_DOWN_AND_HORIZONTAL=┬"
set "GBOX_LIGHT_VERTICAL_AND_RIGHT=├"
set "GBOX_LIGHT_HORIZONTAL=─"
set "GBOX_LIGHT_VERTICAL_AND_HORIZONTAL=┼"
set "GBOX_VERTICAL_SINGLE_AND_RIGHT_DOUBLE=╞"
set "GBOX_VERTICAL_DOUBLE_AND_RIGHT_SINGLE=╟"
set "GBOX_DOUBLE_UP_AND_RIGHT=╚"
set "GBOX_DOUBLE_DOWN_AND_RIGHT=╔"
set "GBOX_DOUBLE_UP_AND_HORIZONTAL=╩"
set "GBOX_DOUBLE_DOWN_AND_HORIZONTAL=╦"
set "GBOX_DOUBLE_VERTICAL_AND_RIGHT=╠"
set "GBOX_DOUBLE_HORIZONTAL=═"
set "GBOX_DOUBLE_VERTICAL_AND_HORIZONTAL=╬"
set "GBOX_UP_SINGLE_AND_HORIZONTAL_DOUBLE=╧"
set "GBOX_UP_DOUBLE_AND_HORIZONTAL_SINGLE=╨"
set "GBOX_DOWN_SINGLE_AND_HORIZONTAL_DOUBLE=╤"
set "GBOX_DOWN_DOUBLE_AND_HORIZONTAL_SINGLE=╥"
set "GBOX_UP_DOUBLE_AND_RIGHT_SINGLE=╙"
set "GBOX_UP_SINGLE_AND_RIGHT_DOUBLE=╘"
set "GBOX_DOWN_SINGLE_AND_RIGHT_DOUBLE=╒"
set "GBOX_DOWN_DOUBLE_AND_RIGHT_SINGLE=╓"
set "GBOX_VERTICAL_DOUBLE_AND_HORIZONTAL_SINGLE=╫"
set "GBOX_VERTICAL_SINGLE_AND_HORIZONTAL_DOUBLE=╪"
set "GBOX_LIGHT_UP_AND_LEFT=┘"
set "GBOX_LIGHT_DOWN_AND_RIGHT=┌"
set "GBOX_FULL_BLOCK=█"
set "GBOX_LOWER_HALF_BLOCK=▄"
set "GBOX_LEFT_HALF_BLOCK=▌"
set "GBOX_RIGHT_HALF_BLOCK=▐"
set "GBOX_UPPER_HALF_BLOCK=▀"
REM Restore the previous console codepage.
chcp.com %CONSOLE_CODEPAGE% >NUL
graphics_test.bat
@echo off
setlocal
set "scriptdir=%~dp0"
call "%scriptdir%\graphics_ctl.bat"
call "%scriptdir%\graphics_box.bat"
echo.
echo ASCII Control-Character Graphics
echo ----------------------------------------------
echo GCTL_WHITE_SMILING_FACE = %GCTL_WHITE_SMILING_FACE%
echo GCTL_BLACK_SMILING_FACE = %GCTL_BLACK_SMILING_FACE%
echo GCTL_BLACK_HEART_SUIT = %GCTL_BLACK_HEART_SUIT%
echo GCTL_BLACK_DIAMOND_SUIT = %GCTL_BLACK_DIAMOND_SUIT%
echo GCTL_BLACK_CLUB_SUIT = %GCTL_BLACK_CLUB_SUIT%
echo GCTL_BLACK_SPADE_SUIT = %GCTL_BLACK_SPADE_SUIT%
echo GCTL_BULLET = %GCTL_BULLET%
echo GCTL_INVERSE_BULLET = %GCTL_INVERSE_BULLET%
echo GCTL_WHITE_CIRCLE = %GCTL_WHITE_CIRCLE%
echo GCTL_INVERSE_WHITE_CIRCLE = %GCTL_INVERSE_WHITE_CIRCLE%
echo GCTL_MALE_SIGN = %GCTL_MALE_SIGN%
echo GCTL_FEMALE_SIGN = %GCTL_FEMALE_SIGN%
echo GCTL_EIGHTH_NOTE = %GCTL_EIGHTH_NOTE%
echo GCTL_BEAMED_EIGHTH_NOTES = %GCTL_BEAMED_EIGHTH_NOTES%
echo GCTL_WHITE_SUN_WITH_RAYS = %GCTL_WHITE_SUN_WITH_RAYS%
echo GCTL_BLACK_RIGHT_POINTER = %GCTL_BLACK_RIGHT_POINTER%
echo GCTL_BLACK_LEFT_POINTER = %GCTL_BLACK_LEFT_POINTER%
echo GCTL_UP_DOWN_ARROW = %GCTL_UP_DOWN_ARROW%
echo GCTL_DOUBLE_EXCLAMATION_MARK = %GCTL_DOUBLE_EXCLAMATION_MARK%
echo GCTL_PILCROW_SIGN = %GCTL_PILCROW_SIGN%
echo GCTL_SECTION_SIGN = %GCTL_SECTION_SIGN%
echo GCTL_BLACK_RECTANGLE = %GCTL_BLACK_RECTANGLE%
echo GCTL_UP_DOWN_ARROW_WITH_BASE = %GCTL_UP_DOWN_ARROW_WITH_BASE%
echo GCTL_UP_ARROW = %GCTL_UP_ARROW%
echo GCTL_DOWN_ARROW = %GCTL_DOWN_ARROW%
echo GCTL_RIGHT_ARROW = %GCTL_RIGHT_ARROW%
echo GCTL_LEFT_ARROW = %GCTL_LEFT_ARROW%
echo GCTL_RIGHT_ANGLE = %GCTL_RIGHT_ANGLE%
echo GCTL_LEFT_RIGHT_ARROW = %GCTL_LEFT_RIGHT_ARROW%
echo GCTL_BLACK_UP_TRIANGLE = %GCTL_BLACK_UP_TRIANGLE%
echo GCTL_BLACK_DOWN_TRIANGLE = %GCTL_BLACK_DOWN_TRIANGLE%
echo GCTL_HOUSE = %GCTL_HOUSE%
echo.
echo Box-Drawing Graphics
echo ----------------------------------------------
echo GBOX_LIGHT_SHADE = %GBOX_LIGHT_SHADE%
echo GBOX_MEDIUM_SHADE = %GBOX_MEDIUM_SHADE%
echo GBOX_DARK_SHADE = %GBOX_DARK_SHADE%
echo GBOX_LIGHT_VERTICAL = %GBOX_LIGHT_VERTICAL%
echo GBOX_LIGHT_VERTICAL_AND_LEFT = %GBOX_LIGHT_VERTICAL_AND_LEFT%
echo GBOX_VERTICAL_SINGLE_AND_LEFT_DOUBLE = %GBOX_VERTICAL_SINGLE_AND_LEFT_DOUBLE%
echo GBOX_VERTICAL_DOUBLE_AND_LEFT_SINGLE = %GBOX_VERTICAL_DOUBLE_AND_LEFT_SINGLE%
echo GBOX_DOWN_DOUBLE_AND_LEFT_SINGLE = %GBOX_DOWN_DOUBLE_AND_LEFT_SINGLE%
echo GBOX_DOWN_SINGLE_AND_LEFT_DOUBLE = %GBOX_DOWN_SINGLE_AND_LEFT_DOUBLE%
echo GBOX_DOUBLE_VERTICAL_AND_LEFT = %GBOX_DOUBLE_VERTICAL_AND_LEFT%
echo GBOX_DOUBLE_VERTICAL = %GBOX_DOUBLE_VERTICAL%
echo GBOX_DOUBLE_DOWN_AND_LEFT = %GBOX_DOUBLE_DOWN_AND_LEFT%
echo GBOX_DOUBLE_UP_AND_LEFT = %GBOX_DOUBLE_UP_AND_LEFT%
echo GBOX_UP_DOUBLE_AND_LEFT_SINGLE = %GBOX_UP_DOUBLE_AND_LEFT_SINGLE%
echo GBOX_UP_SINGLE_AND_LEFT_DOUBLE = %GBOX_UP_SINGLE_AND_LEFT_DOUBLE%
echo GBOX_LIGHT_DOWN_AND_LEFT = %GBOX_LIGHT_DOWN_AND_LEFT%
echo GBOX_LIGHT_UP_AND_RIGHT = %GBOX_LIGHT_UP_AND_RIGHT%
echo GBOX_LIGHT_UP_AND_HORIZONTAL = %GBOX_LIGHT_UP_AND_HORIZONTAL%
echo GBOX_LIGHT_DOWN_AND_HORIZONTAL = %GBOX_LIGHT_DOWN_AND_HORIZONTAL%
echo GBOX_LIGHT_VERTICAL_AND_RIGHT = %GBOX_LIGHT_VERTICAL_AND_RIGHT%
echo GBOX_LIGHT_HORIZONTAL = %GBOX_LIGHT_HORIZONTAL%
echo GBOX_LIGHT_VERTICAL_AND_HORIZONTAL = %GBOX_LIGHT_VERTICAL_AND_HORIZONTAL%
echo GBOX_VERTICAL_SINGLE_AND_RIGHT_DOUBLE = %GBOX_VERTICAL_SINGLE_AND_RIGHT_DOUBLE%
echo GBOX_VERTICAL_DOUBLE_AND_RIGHT_SINGLE = %GBOX_VERTICAL_DOUBLE_AND_RIGHT_SINGLE%
echo GBOX_DOUBLE_UP_AND_RIGHT = %GBOX_DOUBLE_UP_AND_RIGHT%
echo GBOX_DOUBLE_DOWN_AND_RIGHT = %GBOX_DOUBLE_DOWN_AND_RIGHT%
echo GBOX_DOUBLE_UP_AND_HORIZONTAL = %GBOX_DOUBLE_UP_AND_HORIZONTAL%
echo GBOX_DOUBLE_DOWN_AND_HORIZONTAL = %GBOX_DOUBLE_DOWN_AND_HORIZONTAL%
echo GBOX_DOUBLE_VERTICAL_AND_RIGHT = %GBOX_DOUBLE_VERTICAL_AND_RIGHT%
echo GBOX_DOUBLE_HORIZONTAL = %GBOX_DOUBLE_HORIZONTAL%
echo GBOX_DOUBLE_VERTICAL_AND_HORIZONTAL = %GBOX_DOUBLE_VERTICAL_AND_HORIZONTAL%
echo GBOX_UP_SINGLE_AND_HORIZONTAL_DOUBLE = %GBOX_UP_SINGLE_AND_HORIZONTAL_DOUBLE%
echo GBOX_UP_DOUBLE_AND_HORIZONTAL_SINGLE = %GBOX_UP_DOUBLE_AND_HORIZONTAL_SINGLE%
echo GBOX_DOWN_SINGLE_AND_HORIZONTAL_DOUBLE = %GBOX_DOWN_SINGLE_AND_HORIZONTAL_DOUBLE%
echo GBOX_DOWN_DOUBLE_AND_HORIZONTAL_SINGLE = %GBOX_DOWN_DOUBLE_AND_HORIZONTAL_SINGLE%
echo GBOX_UP_DOUBLE_AND_RIGHT_SINGLE = %GBOX_UP_DOUBLE_AND_RIGHT_SINGLE%
echo GBOX_UP_SINGLE_AND_RIGHT_DOUBLE = %GBOX_UP_SINGLE_AND_RIGHT_DOUBLE%
echo GBOX_DOWN_SINGLE_AND_RIGHT_DOUBLE = %GBOX_DOWN_SINGLE_AND_RIGHT_DOUBLE%
echo GBOX_DOWN_DOUBLE_AND_RIGHT_SINGLE = %GBOX_DOWN_DOUBLE_AND_RIGHT_SINGLE%
echo GBOX_VERTICAL_DOUBLE_AND_HORIZONTAL_SINGLE = %GBOX_VERTICAL_DOUBLE_AND_HORIZONTAL_SINGLE%
echo GBOX_VERTICAL_SINGLE_AND_HORIZONTAL_DOUBLE = %GBOX_VERTICAL_SINGLE_AND_HORIZONTAL_DOUBLE%
echo GBOX_LIGHT_UP_AND_LEFT = %GBOX_LIGHT_UP_AND_LEFT%
echo GBOX_LIGHT_DOWN_AND_RIGHT = %GBOX_LIGHT_DOWN_AND_RIGHT%
echo GBOX_FULL_BLOCK = %GBOX_FULL_BLOCK%
echo GBOX_LOWER_HALF_BLOCK = %GBOX_LOWER_HALF_BLOCK%
echo GBOX_LEFT_HALF_BLOCK = %GBOX_LEFT_HALF_BLOCK%
echo GBOX_RIGHT_HALF_BLOCK = %GBOX_RIGHT_HALF_BLOCK%
echo GBOX_UPPER_HALF_BLOCK = %GBOX_UPPER_HALF_BLOCK%