Совместимость printf со строками в кодировке utf-8 - PullRequest
1 голос
/ 25 июня 2019

Я пытаюсь отформатировать некоторые строки в кодировке utf-8 в коде C (char *), используя функцию printf.Мне нужно указать длину в формате.Все идет хорошо, когда в строке параметров нет многобайтовых символов, но результат кажется неправильным, когда в данных есть несколько многобайтовых символов.

мой glibc довольно старый (2.17), поэтому я попыталсяс некоторыми онлайн-компиляторами и результат тот же.

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

int main(void)
{
    setlocale( LC_CTYPE, "en_US.UTF-8" );
    setlocale( LC_COLLATE, "en_US.UTF-8" );

    printf( "'%-4.4s'\n",   "elephant" );
    printf( "'%-4.4s'\n",   "éléphant" );
    printf( "'%-20.20s'\n", "éléphant" );

    return 0;
}

Result of execution is :

'elep'
'él�'
'éléphant          '

Первая строка правильная (4 знака в выводе)

Вторая строка явно неверна (по крайней мере, с человеческой точки зрения)

Последняя строка также неверна: вместо 20

* 1011 записано только 18 символов Юникода * Кажется, что функция printf подсчитывает символы до декодирования UTF-8 (считая байты вместо символов Юникода)

Это ошибка в glibc или хорошо задокументированное ограничение printf?

1 Ответ

1 голос
/ 26 июня 2019

Это правда, что printf считает байты, а не многобайтовые символы. Если это ошибка, ошибка в стандарте C, а не в glibc (реализация стандартной библиотеки, обычно используемая вместе с gcc).

Справедливости ради, подсчет символов также не поможет вам выровнять вывод Unicode, потому что символы Unicode не имеют одинаковую ширину дисплея даже со шрифтами фиксированной ширины. (Многие кодовые точки имеют ширину 0, например.)

Я не собираюсь утверждать, что это поведение "хорошо документировано". Стандартные средства стандарта C никогда не были особенно адекватны задаче, imho, и они никогда не были особенно хорошо документированы, отчасти потому, что базовая модель пытается охватить так много возможных кодировок, даже не опираясь на конкретный пример, что практически невозможно объяснить. (... Длинная разглагольствование удалена ...)

Вы можете использовать отформатированные функции вывода wchar.h , которые считаются широкими символами. (Который все еще не даст вам правильного выравнивания вывода, но он будет считать точность, как вы ожидаете.)

...