【问题标题】:C programming, unicode/UTF-8 special characters not showing up on linux consoleC 编程,unicode/UTF-8 特殊字符未显示在 linux 控制台上
【发布时间】:2020-11-29 13:53:08
【问题描述】:

我是一个 C 初学者,正在尝试这个和那个。

一般来说,我想使用特殊字符"blocks" 来进行某种百分比显示。

一个是3x3 char矩阵上的一种饼图,一个是从下往上往上填充一个char,最后一串两个char应该从左到右显示增长到100%。

基本上它似乎可以解决,但显然我的控制台在显示输出方面存在一些问题。未正确显示的字符似乎导致标准输出不来 \n。

一些研究让我相信终端的语言环境设置(debian 衍生版本上的 bash)在显示字符方面存在一些问题,而 Code::Blocks 在显示字符方面没有问题,甚至显示了一些字符正确。抱歉,我也对这里的 unicode 和 utf-8 感到有些困惑。

在下面的屏幕显示中,您可以看到显示的一些代码、我的语言环境设置以及代码的一些输出。

我该如何解决这个问题?

顺便说一句:如果可能的话,我想坚持使用 printf 以使事情变得容易。

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

// some little helpers
# define hideCursor() printf("\e[?25l")
# define showCursor() printf("\e[?25h")
# define clear() printf("\033[H\033[J")

// # define WIDE_ORIENTED 1

int msleep(long tms);

int main()
{
setlocale(LC_ALL, "");
// fwide( stdout, WIDE_ORIENTED );

char percentage[21][4][4] = {{"   ","   ","   ","  0"},
                             {" ▐ ","   ","   ","  5"},
                             {" ▐▌","   ","   "," 10"},
                             {" ▐▛","   ","   "," 15"},
                             {" ▐█","   ","   "," 20"},
                             {" ▐█","  ▀","   "," 25"},
                             {" ▐█","  █","   "," 30"},
                             {" ▐█","  █","  ▀"," 35"},
                             {" ▐█","  █","  ▜"," 40"},
                             {" ▐█","  █","  █"," 45"},
                             {" ▐█","  █"," ▐█"," 50"},
                             {" ▐█","  █"," ██"," 55"},
                             {" ▐█","  █","▐██"," 60"},
                             {" ▐█","  █","▟██"," 65"},
                             {" ▐█","  █","███"," 70"},
                             {" ▐█","▄ █","███"," 75"},
                             {" ▐█","█ █","███"," 80"},
                             {"▄▐█","█ █","███"," 85"},
                             {"▙▐█","█ █","███"," 90"},
                             {"█▐█","█ █","███"," 95"},
                             {"███","█ █","███","100"}};

char percentageUpwards[10] = {" ▁▂▃▄▅▆▇██"};

char percentageSidewards[20][2] = {"  ","▏ ","▎ ","▍ ","▌ ","▌ ","▋ ","▊ ","█ ","▉ ","▉▏","▉▎","▉▍","▉▌","▉▌","▉▋","▉▊","▉█","▉▉","▉▉"};


// does already nor work :-/
    clear();
    int counter = 0;
    for (int i = 0 ; i <= 100 ; i++) {
    //printf("%d %d\n", (i), (i % 5));
        if ((i % 5) == 0) {
            clear();
            printf("Squared Percentage:\n");
            printf("%s\n",percentage[counter][0]);
            printf("%s\n",percentage[counter][1]);
            printf("%s\n",percentage[counter][2]);
            printf("%s\n",percentage[counter][3]);
            msleep(500); // nappy for easier following
            counter++;
        }
    }

// only a percentage display going upwards
    counter = 0;
    for (int i = 0 ; i <= 100 ; i++) {
        if ((i % 11) == 0) {
            clear();
            printf("Upwards:\n");
            printf("%c\n", percentageUpwards[counter]);
            fflush(stdout);
            printf("%d\n", i);
            msleep(500); // nappy for easier following
            counter++;
        }
    }

// only a percentage display going upwards
    counter = 0;
    for (int i = 0 ; i <= 100 ; i++) {
        if ((i % 5) == 0) {
            clear();
            printf("Sidewards:\n");
            printf("%s\n", percentageSidewards[counter]);
            fflush(stdout);
            printf("%d\n", i);
            msleep(500); // nappy for easier following
            counter++;
        }
    }

// Test only
printf("%s\n", percentage[15][0]);
printf("%s\n", percentage[15][1]);
printf("%s\n", percentage[15][2]);
printf("%s\n", percentage[15][3]);
printf("\n");
printf("%c\n", percentageUpwards[5]);
printf("\n");
printf("%s\n", percentageSidewards[10]);

    return 0;
}

// have a nap in 1/1000th of a second steps
int msleep(long tms)
{
    struct timespec ts;
    int ret;
    if (tms < 0) {
        return -1;
    }
    ts.tv_sec = tms / 1000;
    ts.tv_nsec = (tms % 1000) * 1000000;
    do {
        ret = nanosleep(&ts, &ts);
    }
    while (ret);
    return ret;
}

a simple screenie

【问题讨论】:

  • 检查终端中是否启用了 UTF8。 stackoverflow.com/questions/5306153/…
  • 我怀疑您的 percentage 数组在第三维中需要更多空间 - 将第二个 4 更改为至少 5。我不记得您正在使用的块字符的 Unicode 代码点,但在 UTF-8 中,每个字节至少需要两个甚至三个字节。
  • 也许使用 L" " 语法来处理文字字符串? wchar_t 代表字符。
  • @Florent 谢谢,我仔细检查了,但它是 utf-8。 (另见屏幕截图。)无论如何,我认为你是对的,这是(除了我的数组的尺寸错误)问题。您使用 litteral 字符串和 wchar_t 的解决方案我也读过,但对于我卑微的开端来说似乎有些先进:-)

标签: c unicode utf-8 printf locale


【解决方案1】:

正如我在comment 中猜测的那样,主要问题是您的代码试图在太小的数组中存储太多数据。

当我复制您的代码时,它无法编译,因为初始化数组的字符串太大。您使用的字符似乎在 U+2580..U+259F 范围内,这意味着它们在以 UTF-8 表示时需要 3 个字节(U+2580 = 0xE2 0x96 0x80 = U+2580;0xE2 0x96 0x9F = U+259F)。

您必须增加数组的大小——当使用 charsigned charunsigned char 时,C 会计算字节数,而不是字符数。使用16 太过分了; 10 就足够了;同样8 可能只是7。您还需要将percentageUpwards 数组视为至少大小为 4 的字符串数组。将这些更改放在一起会产生此代码,该代码或多或少适用于运行 macOS 10.14.6 Mojave 的 Mac 和 Linux运行 RHEL Server 版本 7.4 (Maipo) 的盒子——后者通过ssh 运行到 Mac 上的终端中。

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

// some little helpers
# define hideCursor() printf("\e[?25l")
# define showCursor() printf("\e[?25h")
# define clear() printf("\033[H\033[J")

// # define WIDE_ORIENTED 1

int msleep(long tms);

int main(void)
{
    setlocale(LC_ALL, "");
// fwide( stdout, WIDE_ORIENTED );

    char percentage[21][4][16] =
    {
        { "   ", "   ", "   ", "  0" },
        { " ▐ ", "   ", "   ", "  5" },
        { " ▐▌", "   ", "   ", " 10" },
        { " ▐▛", "   ", "   ", " 15" },
        { " ▐█", "   ", "   ", " 20" },
        { " ▐█", "  ▀", "   ", " 25" },
        { " ▐█", "  █", "   ", " 30" },
        { " ▐█", "  █", "  ▀", " 35" },
        { " ▐█", "  █", "  ▜", " 40" },
        { " ▐█", "  █", "  █", " 45" },
        { " ▐█", "  █", " ▐█", " 50" },
        { " ▐█", "  █", " ██", " 55" },
        { " ▐█", "  █", "▐██", " 60" },
        { " ▐█", "  █", "▟██", " 65" },
        { " ▐█", "  █", "███", " 70" },
        { " ▐█", "▄ █", "███", " 75" },
        { " ▐█", "█ █", "███", " 80" },
        { "▄▐█", "█ █", "███", " 85" },
        { "▙▐█", "█ █", "███", " 90" },
        { "█▐█", "█ █", "███", " 95" },
        { "███", "█ █", "███", "100" },
    };

    char percentageUpwards[][4] =
    {
        " ", "▁", "▂", "▃", "▄", "▅", "▆", "▇", "█", "█", 
    };

    char percentageSidewards[20][8] =
    {
        "  ", "▏ ", "▎ ", "▍ ", "▌ ", "▌ ", "▋ ", "▊ ", "█ ", "▉ ",
        "▉▏", "▉▎", "▉▍", "▉▌", "▉▌", "▉▋", "▉▊", "▉█", "▉▉", "▉▉",
    };

    // does already not work :-/
    clear();
    int counter = 0;
    for (int i = 0; i <= 100; i++)
    {
        // printf("%d %d\n", (i), (i % 5));
        if ((i % 5) == 0)
        {
            clear();
            printf("Squared Percentage:\n");
            printf("%s\n", percentage[counter][0]);
            printf("%s\n", percentage[counter][1]);
            printf("%s\n", percentage[counter][2]);
            printf("%s\n", percentage[counter][3]);
            msleep(500); // nappy for easier following
            counter++;
        }
    }

    // only a percentage display going upwards
    counter = 0;
    for (int i = 0; i <= 100; i++)
    {
        if ((i % 11) == 0)
        {
            clear();
            printf("Upwards:\n");
            printf("%s\n", percentageUpwards[counter]);
            fflush(stdout);
            printf("%d\n", i);
            msleep(500); // nappy for easier following
            counter++;
        }
    }

    // only a percentage display going upwards
    counter = 0;
    for (int i = 0; i <= 100; i++)
    {
        if ((i % 5) == 0)
        {
            clear();
            printf("Sidewards:\n");
            printf("%s\n", percentageSidewards[counter]);
            fflush(stdout);
            printf("%d\n", i);
            msleep(500); // nappy for easier following
            counter++;
        }
    }

    // Test only
    printf("%s\n", percentage[15][0]);
    printf("%s\n", percentage[15][1]);
    printf("%s\n", percentage[15][2]);
    printf("%s\n", percentage[15][3]);
    printf("\n");
    printf("%s\n", percentageUpwards[5]);
    printf("\n");
    printf("%s\n", percentageSidewards[10]);

    return 0;
}

// have a nap in 1/1000th of a second steps
int msleep(long tms)
{
    struct timespec ts;
    int ret;
    if (tms < 0)
    {
        return -1;
    }
    ts.tv_sec = tms / 1000;
    ts.tv_nsec = (tms % 1000) * 1000000;
    do
    {
        ret = nanosleep(&ts, &ts);
    }while (ret);
    return ret;
}

我无法明智地显示输出;由于msleep() 调用,它是动态的,执行大约需要 26 秒。

【讨论】:

  • 谢谢,这已经很有帮助了。我现在明白我的数组需要解决的大小不是 char 而是存储所需的字节。您的代码在我的 debain 衍生品上开箱即用,并且显示已经正确的百分比计数。所以在后台,从逻辑和句法的角度来看,这很好。不幸的是,输出中仍然部分显示了一些虚拟字符,它们破坏了“字符动画,分别是字符串”的效果。
猜你喜欢
  • 1970-01-01
  • 2012-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-19
  • 2010-11-25
  • 2020-09-20
相关资源
最近更新 更多