方框字符在 Linux 终端中无法正确显示

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

使用以下命令编译此演示:

\n
g++ -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

或者

\n
LDLIBS=-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

它显示这个:

\n
M-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)\n

实际屏幕图像

\n

macOS 上的正常(所需)显示:

\n

macOS 上的正常(所需)显示

\n

Linux下显示异常:

\n

Linux下显示异常

\n

roa*_*ima 16

问题是您使用的是文字字符\xe2\x94\x8c, \xe2\x94\x80, \xe2\x94\x90, \xe2\x94\x94, \xe2\x94\x80\xe2\x94\x98而不是使用ncurses独立的符号。您应该使用ACS_??CORNER(对于Upper/ Lower 和Left/ Right)和ACS_HLINE符号名称,并让ncurses我们弄清楚如何在终端上表示这些名称。

\n

从此修改您的代码,

\n
mvprintw(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

对此,

\n
move(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为以下内容,以便在程序结束时正确重置终端:

\n
endwin();\nexit(0);\n
Run Code Online (Sandbox Code Playgroud)\n

编译test.cpp并执行,

\n
LDLIBS=-lncurses make test && ./test\n
Run Code Online (Sandbox Code Playgroud)\n

有用的参考资料,排名不分先后:

\n\n


Tho*_*key 10

在 MacOS 上,-lncursesncurses 的宽字符配置的链接通常由-lncursesw. 这setlocale调用给出了不同的结果(正常字符与宽字符),并且框字符的文字字符串(UTF-8)的结果也不同。

\n

进一步阅读:

\n\n
\n
    \n
  • 大于 128 的值要么是元字符(如果屏幕尚未初始化,或者使用 TRUE 参数调用了 meta(3x)),以MX表示法显示,要么单独显示。在后一种情况下,这些值可能无法打印;这遵循 X/Open 规范。
  • \n
\n
\n

根本问题是框字符的 UTF-8 编码使用高于 128 的字节码,并且如果没有宽字符库中使用的区域设置支持,您将得到\xe2\x80\x94no 重组字节转换为宽字符。

\n

其他一些平台也-lncurses作为 的别名出现-lncursesw,例如(注意注释)Arch Linux,其中有/usr/lib/ncurses.so

\n
INPUT(-lncursesw)\n
Run Code Online (Sandbox Code Playgroud)\n

另一条评论询问了“粗线”。这里有几点:

\n\n
\n

我只为粗线/双线实现了 WACS_xxx 符号,原因如下:它是实验性的,仅对 Unicode 有用。

\n
\n
    \n
  • 这些符号记录在wadd_wch手册页中。
  • \n
  • 该功能不适用于 MacOS 的捆绑 ncurses,因为它(ncurses 5.7)比 ncurses 的更改早了大约一年。
  • \n
  • 它不适用于 Linux 控制台终端(因为它依赖于只有 512 个字形的字体)。
  • \n
  • 粗/双线的实际外观未指定(取决于字体)。
  • \n
\n


she*_*ish 3

问题是方框字符在 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

如果您希望自动使您的代码交叉兼容此问题,\n请将其放入您的 makefile 中。

\n
ifneq ($(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