Программа, обрабатывающая символы строки

Написал программу, которая проходит по строке и считает, сколько раз встречается каждый символ. В консоли программа выводит символы (по возрастанию их кодов в кодировке) и их количество повторений. Но проблема в том, что с некоторыми строками возникают проблемы. Так он неверно считывает строку є№ё·¶µґіІ±°Ї®­¬«Є©Ё§¦Ґ¤ и выводит неправильные символы и их подсчёт. Скорее всего, это связано с тем, что эти символы не входят в кодировку ASCII. Для символов в пределах этой кодировки всё работает, но с символами из unicode уже беда.

#include <stdio.h>

int main() {
    unsigned char input_string[81000];
    fgets(input_string, sizeof(input_string), stdin);

    int char_counts[100000] = {0};

    for (int i = 0; input_string[i] != '\0'; i++) {
        char_counts[(int)input_string[i]]++;
    }

    for (int i = 0; i < 100000; i++) {
        if (char_counts[i] > 0 && (char)i != '\n') {
            printf("%c=%d\n", (char)i, char_counts[i]);
        }
    }

    return 0;
}

Изменение 04.12.2023:

Использовал библиотеку wchar.h

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

int main() {
    setlocale(LC_ALL, ""); // установка локали
    wchar_t input_string[81000];
    fgetws(input_string, sizeof(input_string), stdin);

    int char_counts[65536] = { 0 }; // расширение до 65536 для поддержки Unicode

    for (int i = 0; input_string[i] != '\0'; i++) {
        char_counts[(int)input_string[i]]++;
    }

    for (int i = 0; i < 65536; i++) {
        if (char_counts[i] > 0 && (wchar_t)i != '\n') {
            wprintf(L"%lc=%d\n", (wchar_t)i, char_counts[i]);
        }
    }

    return 0;
}

Но весь смех в том, что в онлайн компиляторе всё корректно работает, а на моём visual studio вместо некоторых символов печатаются просто пробелы)) Менял настройки кодировок проекта, но это не помогло. Хочу вообще понять, можно ли решить данную задачу без использования сторонних библиотек, таких как wchar?


Ответы (1 шт):

Автор решения: Stanislav Volodarskiy

Код ниже разбирает текст в кодировке UTF8 на отдельные символы. Сделан грубо, но работает. Как пример сойдёт:

#include <stdbool.h>
#include <stdio.h>

bool read_utf8_char(int *ord, char s[5]) {
    int chr = getc(stdin);
    if (chr == EOF) {
        return false;
    }
    s[0] = (char)chr;

    int k = 0;
    if (chr >> 7 == 0) {
        *ord = chr;
    } else if (chr >> 5 == 6) {
        k = 1;
        *ord = chr & 31;
    } else if (chr >> 4 == 14) {
        k = 2;
        *ord = chr & 15;
    } else if (chr >> 3 == 30) {
        k = 3;
        *ord = chr & 7;
    }
    for (int i = 0; i < k; ++i) {
        int chr = getc(stdin);
        if (chr == EOF) {
            return false;
        }
        s[i + 1] = (char)chr;
        *ord = (*ord << 6) | (chr & 63);
    }
    s[k + 1] = '\0';
    return true;
}

int main() {
    int ord;
    char s[5];
    while (read_utf8_char(&ord, s)) {
        printf("%s %10d %10x\n", ((ord < 32) ? "?" : s), ord, ord);
    }
}
$ gcc -std=c11 -pedantic -Wall -Wextra -Werror -Wwrite-strings -Wconversion dump-chars.c

$ echo "є№ё·¶µґіІ±°Ї®­¬«Є©Ё§¦Ґ¤" | ./a.out
є       1108        454
№       8470       2116
ё       1105        451
·        183         b7
¶        182         b6
µ        181         b5
ґ       1169        491
і       1110        456
І       1030        406
±        177         b1
°        176         b0
Ї       1031        407
®        174         ae
­        173         ad
¬        172         ac
«        171         ab
Є       1028        404
©        169         a9
Ё       1025        401
§        167         a7
¦        166         a6
Ґ       1168        490
¤        164         a4
?         10          a
→ Ссылка