she*_*ish 8 terminal unicode cpp
我刚刚编写了一个 C++] 程序,它使用方框字符来显示信息。\xc2\xa0\nI\xc2\xa0在 macOS 上运行该程序并使用终端应用程序,它运行良好。
\n当我使用相同的代码切换到Debian Linux并重新编译它时,\n我\xc2\xa0才遇到这个问题!\xc2\xa0\n我\在网上搜索了答案,\n但我\xc2\xa0没有找到与这个问题。\xc2\xa0\n我已经\xc2\xa0 使用LXTerminal和\xc2\xa0 URXVT测试了这个问题。
\n这是这个问题的最小可重现示例:
\n#include <ncurses.h>\n#include <iostream>\n\nint ch;\n\nint main() {\n setlocale(LC_CTYPE, "");\n initscr();\n noecho();\n keypad(stdscr, true);\n nodelay(stdscr, true);\n curs_set(0);\n start_color();\n use_default_colors();\n\n init_pair(1, COLOR_BLUE, -1);\n\n clear();\n refresh();\n\n while ((ch = getch()) != \'q\' && ch != \'Q\') {\n\n attrset(COLOR_PAIR(1));\n\n mvprintw(0,0,"\xe2\x94\x8f\xe2\x94\x81\xe2\x94\x93");\n mvprintw(1,0,"\xe2\x94\x97\xe2\x94\x81\xe2\x94\x9b");\n\n }\n\n refresh();\n endwin();\n\n return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n使用以下命令编译此演示:
\ng++ -g -c -o main.o test.cpp && g++ -g -o test main.o -std=c++11 -Wall -pedantic -lncurses\n
Run Code Online (Sandbox Code Playgroud)\n或者
\nLDLIBS=-lncurses make test\n
Run Code Online (Sandbox Code Playgroud)\n而不是显示
\n\xe2\x94\x8f\xe2\x94\x81\xe2\x94\x93\n\xe2\x94\x97\xe2\x94\x81\xe2\x94\x9b\n
Run Code Online (Sandbox Code Playgroud)\n它显示这个:
\nM-b~T~OM-b~T~AM-b~T~S\nM-b~T~WM-b~T~AM-b~T~[\n
Run Code Online (Sandbox Code Playgroud)\nmacOS 上的正常(所需)显示:
\n\nLinux下显示异常:
\n\nroa*_*ima 16
问题是您使用的是文字字符\xe2\x94\x8c
, \xe2\x94\x80
, \xe2\x94\x90
, \xe2\x94\x94
, \xe2\x94\x80
,\xe2\x94\x98
而不是使用ncurses
独立的符号。您应该使用ACS_??CORNER
(对于U
pper/ L
ower 和L
eft/ R
ight)和ACS_HLINE
符号名称,并让ncurses
我们弄清楚如何在终端上表示这些名称。
从此修改您的代码,
\nmvprintw(0,0,"\xe2\x94\x8f\xe2\x94\x81\xe2\x94\x93");\nmvprintw(1,0,"\xe2\x94\x97\xe2\x94\x81\xe2\x94\x9b");\n
Run Code Online (Sandbox Code Playgroud)\n对此,
\nmove(0,0); addch(ACS_ULCORNER); addch(ACS_HLINE); addch(ACS_URCORNER);\nmove(1,0); addch(ACS_LLCORNER); addch(ACS_HLINE); addch(ACS_LRCORNER);\n
Run Code Online (Sandbox Code Playgroud)\n应确保代码可移植地工作。我还将程序的结尾main()
从简单的更改return 0
为以下内容,以便在程序结束时正确重置终端:
endwin();\nexit(0);\n
Run Code Online (Sandbox Code Playgroud)\n编译test.cpp
并执行,
LDLIBS=-lncurses make test && ./test\n
Run Code Online (Sandbox Code Playgroud)\n有用的参考资料,排名不分先后:
\n\nTho*_*key 10
在 MacOS 上,-lncurses
ncurses 的宽字符配置的链接通常由-lncursesw
. 这setlocale
调用给出了不同的结果(正常字符与宽字符),并且框字符的文字字符串(UTF-8)的结果也不同。
进一步阅读:
\n\n\n\n
\n- 大于 128 的值要么是元字符(如果屏幕尚未初始化,或者使用 TRUE 参数调用了 meta(3x)),以MX表示法显示,要么单独显示。在后一种情况下,这些值可能无法打印;这遵循 X/Open 规范。
\n
根本问题是框字符的 UTF-8 编码使用高于 128 的字节码,并且如果没有宽字符库中使用的区域设置支持,您将得到\xe2\x80\x94no 重组字节转换为宽字符。
\n其他一些平台也-lncurses
作为 的别名出现-lncursesw
,例如(注意注释)Arch Linux,其中有/usr/lib/ncurses.so
:
INPUT(-lncursesw)\n
Run Code Online (Sandbox Code Playgroud)\n另一条评论询问了“粗线”。这里有几点:
\n\n\n我只为粗线/双线实现了 WACS_xxx 符号,原因如下:它是实验性的,仅对 Unicode 有用。
\n
wadd_wch
手册页中。问题是方框字符在 Linux 终端中无法正确显示。解决方案是您需要以不同的方式编译代码。
\n如果您正在使用 ncursesprintw
或其他一些使用 ncurses 作为库的文本显示方法,那么这将适用于您。\xc2\xa0\n这取决于操作系统,因此如果您在 macOS 上,您将使用 \xc2\xa0 标志-lncurses
\ n编译时(也根据@terdon,这也适用于Arch Linux,\n但我\xc2\xa0haven\没有测试过),\n如果你使用的是 Linux\n(我\'ve\xc2\xa0仅测试了它Debian)你需要使用-lncursesw
标志。
如果您希望自动使您的代码交叉兼容此问题,\n请将其放入您的 makefile 中。
\nifneq ($(OS),Windows_NT)\n UNAME_S := $(shell uname -s)\n ifeq ($(UNAME_S),Linux)\n NCURSES += -lncursesw\n endif\n ifeq ($(UNAME_S),Darwin)\n NCURSES += -lncurses\n endif\nendif\n
Run Code Online (Sandbox Code Playgroud)\n