在UTF-8中读取ncurses标准输入

4

在我用ncurses开发的Linux程序中,需要以UTF-8编码读取stdin。但是,每当我执行以下操作时:

wint_t unicode_char=0;
get_wch(&unicode_char);

我在使用utf-16编码时获得了宽字符(当我使用gdb转储变量时可以看到)。我不想将其从utf-16转换为utf-8,我希望始终强制输入为UTF-8,而不管用户使用哪个Linux发行版以及所配置的任何外语。如何做到这一点?这是否可能?
编辑:以下是示例源代码和证明,内部get_wch使用的是UTF-16(与UTF-32相同),而不是UTF-8,尽管我已经使用setlocale()配置了UTF-8输入源。
[niko@dev1 ncurses]$ gcc -g -o getch -std=c99 $(ncursesw5-config --cflags --libs) getch.c 
[niko@dev1 ncurses]$ cat getch.c 
#define _GNU_SOURCE
#include <locale.h>
#include <ncursesw/ncurses.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int ct;
wint_t unichar;

int main(int argc, char *argv[])
{
    setlocale(LC_ALL, ""); /* make sure UTF8 */
    initscr();
    raw();
    keypad(stdscr, TRUE);
    ct = get_wch(&unichar); /* read character */
    mvprintw(24, 0, "Key pressed is = %4x ", unichar);

    refresh();
    getch();
    endwin();
    return 0;
}

使用GDB测试代码:


Breakpoint 1, main (argc=1, argv=0x7fffffffded8) at getch.c:18
18      mvprintw(24, 0, "Key pressed is = %4x ", unichar);
Missing separate debuginfos, use: dnf debuginfo-install ncurses-libs-5.9-21.20150214.fc23.x86_64
(gdb) print unichar
$1 = 128270
(gdb) print/x ((unsigned short*) (&unichar))[0]
$2 = 0xf50e
(gdb) print/x ((unsigned short*) (&unichar))[1]
$3 = 0x1
(gdb) print/x ((unsigned char*) (&unichar))[0]
$4 = 0xe
(gdb) print/x ((unsigned char*) (&unichar))[1]
$5 = 0xf5
(gdb) print/x ((unsigned char*) (&unichar))[2]
$6 = 0x1
(gdb) print/x ((unsigned char*) (&unichar))[3]
$7 = 0x0
(gdb) 

输入字符为,其UTF-8应为'f09f948e',如此处所述:http://www.fileformat.info/info/unicode/char/1f50e/index.htm 如何直接从 get_wch() 获取 UTF8?或者还有另一个函数吗?
附注:如果您测试源代码,请链接 '-lncursesw',而不是'-lncurses',或者使用与上面相同的命令进行编译。

1
如果你想要UTF-8,那么为什么要读取宽字符?顺便说一句,在Linux上使用UTF-16通常不被随意支持的随机软件所支持。你可能得到的是UCS4。 - n. m.
2
@Nulik 是的,UTF-8可以使用多个字节进行编码。但是getch()只会读取1个字节。您当前的方法最有可能在任何地方都能正常工作。get_wch()将转换输入为所使用的任何编码,并且mvprintw()将将输出转换回用户使用的编码(大多数情况下两者都将是UTF-8)。 将单个整数视为多字节编码的UTF-8字符是您不需要做的事情 - 您是否有通过这样做解决特定问题的问题? - nos
getch 返回一个转换为 int 的单个字节,但是一个字符可能占据多个字节。因此,您需要多次调用 getch() 来读取单个 Unicode 字符。 - n. m.
@nos 我只想在我的程序中处理所有字符串为UTF-8格式,如果我们能将用户输入设置为UTF-8,就可以避免转换步骤。 - Nulik
@n.m. 你已经得到了我问题的部分答案,我测试了多次getch(),并且得到了正确的输入,即'f09f948e'。由于它是4字节序列,所以我必须执行4次getch()。但现在的问题是,如果用户复制/粘贴多个多字节字符,我如何知道字符序列的结束分隔符呢? - Nulik
显示剩余8条评论
1个回答

2
简短来说,您无法从get_wch中获取UTF-8编码,它会返回wint_t(以及状态码)。
更详细地说,使用ncurses的getch可以获得UTF-8编码,因为它在内部进行wchar_t转换:
1. 您的程序必须逐字节读取编码字符,因为getch仅返回字节(可能与视频属性组合)。
2. ncurses将wchar_t值存储在每个窗口结构的单元格中。
3. addch等函数尝试收集多字节编码的字节(这不是特定于UTF-8的,但除此之外几乎没有用处)。
4. 如果您在字符串中间移动光标,则尝试失败。
值得一提的是,dialog使用getch读取UTF-8。请参见inputstr.c以了解其实际工作原理。
X / Open curses本身不支持此功能(对于实际使用Unix curses的少数人而言,没有指定的方法)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接