Printf () заботится о локали? - PullRequest
0 голосов
/ 04 июня 2018

wprintf() принимает строку wchar_t в качестве аргумента и печатает строку в указанной кодировке символов локали.

Но я заметил, что при использовании printf() и передаче ему строки UTF-8,строка UTF-8 будет всегда печататься независимо от указанной кодировки символов локали (например, если строка UTF-8 содержит арабские символы, а локаль установлена ​​на «C» (не «C.UTF-8»),тогда арабские символы все равно будут напечатаны).

Я правильно понял, что printf() не заботится о локали?

Ответы [ 3 ]

0 голосов
/ 04 июня 2018

Это одно из больших достоинств (возможно, самое большое достоинство) UTF-8: это просто ряд разумно простых байтов. Если ваша среда редактирования кода знает, как разрешить вводить

printf("Cööl!\n");

и , если ваша среда отображения(например, окно вашего терминала) знает, как его отобразить, вы можете просто написать это и запустить, и это работает (как кажется, вы обнаружили).

Так что вам не нужен специальный запускподдержка времени, вам не нужны специальные заголовочные файлы или библиотеки или что-то еще, вам не нужно писать свой код каким-то необычным новым способом Unicodey - вы можете просто продолжать использовать обычные строки C и printf и таких друзей, каквы привыкли, и все это просто работает.

Конечно, эти два , если , могут быть большими.Если вы не можете понять, как (или ваша среда редактирования кода не позволяет вам) вводить символы, или если ваша среда отображения не отображает их, возможно, вы застряли или вам придется проделать тяжелую работув конце концов.(Среды отображения, которые не отображают должным образом выходные данные UTF-8 из программ на C, очевидно, довольно распространены, в зависимости от того, сколько раз вопрос задают здесь на SO.)

См. Также " UTF-8 Everywhere"манифест.

(Теперь, с учетом всего сказанного, это не означает, что printf вообще не заботится о настройках локали. Существуют аспекты локали, которыеprintf может заботиться, и могут быть наборы символов и кодировки, которые printf, возможно, должны будут обрабатывать особым образом, в зависимости от локали. Но так как printf не должен делать ничего особенного, чтобы сделать UTF-8работать правильно, этот один аспект локали - хотя это важная персона - не в конечном итоге влияет на printf вообще.)

0 голосов
/ 05 июня 2018

Рассмотрим следующую простую программу, которая использует printf() для печати широкой строки, если она запускается без аргументов командной строки, и wprintf() в противном случае:

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

const wchar_t hello1[] = L"تحية طيبة";
const wchar_t hello2[] = L"Tervehdys";

int main(int argc, char *argv[])
{
    if (!setlocale(LC_ALL, ""))
        fprintf(stderr, "Warning: Current locale is not supported by the C library.\n");

    if (argc <= 1) {
        printf("printf 1: %ls\n", hello1);
        printf("printf 2: %ls\n", hello2);
    } else {
        wprintf(L"wprintf: %ls\n", hello1);
        wprintf(L"wprintf: %ls\n", hello2);
    }

    return EXIT_SUCCESS;
}

Использование библиотеки GNU C и любых другихЯзык UTF-8:

$ ./example
printf 1: تحية طيبة
printf 2: Tervehdys

$ ./example wide
wprintf: تحية طيبة
wprintf: Tervehdys

, т. Е. Оба дают одинаковый вывод.Однако, если мы запустим пример в локали C / POSIX (которая поддерживает только ASCII), мы получим

$ LANG=C LC_ALL=C ./example
printf 1: printf 2: Tervehdys

, т. Е. Первый printf() остановился на первом не-ASCII-символе (и поэтомувторой printf(), напечатанный в той же строке);

$ LANG=C LC_ALL=C ./example wide
wprintf: ???? ????
wprintf: Tervehdys

т.е. wprintf() заменяет широкие символы, которые не могут быть представлены в кодировке, используемой текущей локалью, на ?.

Итак, если мы рассмотрим библиотеку GNU C (которая демонстрирует такое поведение), то мы должны сказать да, printf заботится о локали , хотя на самом деле она в основном заботится о наборе символов, используемом локалью,а не локаль как таковая:

printf() остановится при попытке печати широких строк, которые не могут быть представлены текущим набором символов (как определено локалью).
wprintf() вместо этого выведет вопросительные знаки для этих символов.

libc6-2.23-0ubuntu10 на x86-64 (amd64) делает некоторые замены для многобайтовых символов в строке формата printf, но многобайтовыхсимволы в строках, напечатанные с %s, печатаются как есть.Это означает, что немного сложно точно сказать, что печатается, и когда printf() отказывается от первого многобайтового или широкого символа, который он не может преобразовать, или просто печатает как есть.

Однако wprintf()довольно твердое тело(Это также может задушить, если вы попытаетесь напечатать узкие строки с многобайтовыми символами, которые не могут быть представлены в наборе символов, используемом в текущей локали, но для широких строк это, кажется, работает очень хорошо.)

Обратите внимание, чтоБиблиотеки POSIX.1 C также предоставляют iconv_open(), iconv() и iconv_close() для преобразования строк, а также mbstowcs() и wcstombs() для преобразования между широкими и узкими / многобайтовыми строками.Вы также можете использовать asprintf() для создания динамически выделяемой узкой строки из строк узких и / или широких символов (%s и %ls соответственно).

0 голосов
/ 04 июня 2018

True printf не заботится о локали для c-строк.Если вы передаете ей строку UTF-8, она ничего не знает об этом, она просто видит последовательность байтов (возможно, завершенную ascii NUL).Затем байты передаются на выход как есть и интерпретируются терминалом (или чем-то еще, что является выходом).Если терминал способен интерпретировать последовательности UTF-8, он делает это (если нет, он пытается интерпретировать его так, как он сконфигурирован, Latin-1 или аналогичный), и если он также способен печатать их правильно, он делает это(иногда он не имеет правильного шрифта / глифа и печатает неизвестные символы как? или так).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...