【问题标题】:Handling Unicode characters in C and NCURSES在 C 和 NCURSES 中处理 Unicode 字符
【发布时间】:2025-12-26 20:20:14
【问题描述】:

我正在尝试在 C 程序中显示一些 unicode 字符。一个工作的 MWE 如下所示:

#include <ncurses.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <locale.h>


int main(int argc, char *argv[]) 
{ 
    setlocale(LC_ALL, "");
    initscr();              // Initialize stdscr

    for(int x = 0; x < 20; x++)
    {
        switch (x%5)
        {
            case 0:
                mvaddstr(1, x, "\u2588");
                break;
            case 1:
                mvaddstr(1, x, "\u2593");
                break;
            case 2:
                mvaddstr(1, x, "\u2592");
                break;
            case 3:
                mvaddstr(1, x, "\u2591");
                break;
            case 4:
                mvaddstr(1, x, " ");
                break;
        }
    }

    mvprintw(3, 0, "Press ANY KEY to finish");
    refresh();
    int ch = getch();
    endwin();

    return 0;
}

编译使用gcc -o shades shades.c -lncursesw。它可以正常编译并正确显示阴影,如下图所示。

但是使用case/switch 语句,我想将我的字符放入十六进制代码的array 中并对其进行迭代。正如下面的可耻尝试。

#include <ncurses.h>
#include <stdlib.h>
#include <stdio.h>
#include <locale.h>

int main(int argc, char *argv[]) 
{ 
    setlocale(LC_ALL, "");
    initscr();              // Initialize stdscr

    uint shades[5] = { 0x2588,
                       0x2593,
                       0x2592,
                       0x2591,
                       ' '};

    char utfchar[7];

    for(int x = 0; x < 20; x++)
    {
        sprintf(utfchar, "\\u%04x", shades[x%5]);
        mvaddstr(1, x, utfchar);
    }

    mvprintw(3, 0, "Press ANY KEY to finish");
    refresh();

    int ch = getch();
    endwin();

    return 0;
}

这里我使用sprintf 将十六进制值转换为格式为\u0000 的字符串,其中0000 是正确的十六进制值。然后我像在之前的代码中一样使用mvaddstr,因为mvaddstr 在第三个参数中需要const char *

这是众多失败的尝试之一。我无法以 unicode 格式正确复制字符串,当我尝试添加 unicode 内容时,也无法将变量用作mvaddstr 的参数。

我想知道如何从 uint 有效的 unicode 十六进制值格式化支持 unicode 的 const char * 以将其插入到 mvaddstr

PS:我在 Linux 中使用的不是 C++,而是纯 C。 C++ 解决方案不是解决方案

【问题讨论】:

  • 也许将数组更改为const char * shades[5] = { "\u2588", "\u2593", "\u2592", "\u2591", ""};
  • 对字符串和字符中的转义序列(如"\u2588")的解析是在编译时由编译器自己完成的。您不能在运行时创建转义序列。至于什么例如"\u2588" 正在做,它只是将十六进制数 0x2588 插入到字符串中(字节顺序不确定)。
  • C 中没有函数可以将十六进制值编码为有效的 unicode?无论如何,使用const char 数组的想法是可行的。但是由于字符值是在我的代码中半动态生成的。我希望能够在运行时将十六进制值 encode 转换为有效的 unicode 字符。
  • 您可以使用wchar 函数,只要您的系统和语言环境期望wchar 保存一个unicode 代码点。 Ncurses 具有广泛的字符支持;例如,参见*.com/questions/15222466/…

标签: c unicode ncurses


【解决方案1】:

您可以简单地将字符串放入数组中:

const char *shades[] = { "\u2588",
                         "\u2593",
                         "\u2592",
                         "\u2591",
                         " "};

for(int x = 0; x < 20; x++)
{
    mvaddstr(1, x, shades[x%4]);
}

如果你想用代码点来做,你需要将它编码为 UTF8(或任何 Ncurse 期望的):

void sprintutf8(char *buffer, uint32_t code)
{
    if (code < 0x80)
        sprintf(buffer, "%c", code);
    else if (code < 0x800)
        sprintf(buffer, "%c%c",
            0xC0 | (code >> 6),
            0x80 | (code & 0x3F));
    else
        sprintf(buffer, "%c%c%c",
            0xE0 | (code >> 12),
            0x80 | (code >> 6 & 0x3F),
            0x80 | (code & 0x3F));
}

[...]

for(int x = 0; x < 20; x++)
{
    sprintutf8(utfchar, shades[x%4]);
    mvaddstr(1, x, utfchar);
}

【讨论】:

  • 我不知道 unicode 规范的实习生细节。这个代码机器字节序安全吗?没有任何标准的 C 函数来处理 unicode 编码?
  • 此代码是字节序安全的,因为它使用位运算符。有人尝试在 C 中获取widechar,恕我直言,处理得不好,我建议不要走那条路(如果你想的话,搜索一下wchar_t)
【解决方案2】:

您可以简单地使用wctomb 转换和wchar_t 将十六进制转换为Unicode:

uint shades[5] = { 0x2588,
                   0x2593,
                   0x2592,
                   0x2591,
                   ' '};

char utfchar[MB_CUR_MAX];

for(int x = 0; x < 20; x++)
{
    memset(utfchar, 0, sizeof utfchar);
    wctomb(utfchar, (wchar_t)shades[x % 5]);
    mvaddstr(1, x, utfchar);
}

【讨论】: