2012-04-04 7 views
5

При использовании Printf для форматирования строки двухбайтовая в однобайтной строку:Почему параметры формата unicode не печатаются?

printf("%ls\n", L"s:\\яшертыHello"); // %ls for a wide string (%s varies meaning depending on the project's unicode settings). 

Очевидно, что некоторые символы не могут быть представлены в виде ASCII-символов, так что иногда я видел поведение, где двухбайтовые символы превратиться в "?" знак. Но, похоже, это зависит от конкретных персонажей. Для приведенного выше Printf, выход:

s:\ 

Я надеялся, что я мог бы получить что-то вроде:

s:\??????Hello 

Боюсь, я потерял пример, но я думаю, что за одну строку, когда он столкнулся с символами юникода, заменил первый на «?» а затем остался на отдыхе.

Итак, мой вопрос: что должно произойти, когда вы форматируете широкую строку в однобайтную строку. Документация здесь: http://msdn.microsoft.com/en-us/library/hf4y5e3w.aspx говорит: «Символы отображаются до первого нулевого символа». Но я этого не вижу. Является ли это ошибкой в ​​printf, или это поведение, которое я вижу где-то где-то, где-то, где.

Благодарим за помощь.

UPDATE

Спасибо за ответы от людей, давая мне альтернативы использованию Printf. Я собираюсь перейти на альтернативу, но меня действительно интересует любопытство, почему printf не имеет надежного документированного поведения. Это похоже на то, что его разработчик вышел из своего пути, чтобы это не сработало.

+2

Вы пробовали «% S» в качестве спецификатора формата вместо «% ls»? –

+0

есть. Я считаю, что% S и% ls имеют то же значение, если у вашего проекта нет UNICODE. –

+1

Чтение спецификаций формата (что я не согласен). S - для широкоформатной строки, если в настройках вашего проекта нет UNICODE, S - для однобайтовой строки, если у вас определен UNICODE. % ls для широкоформатной строки независимо от того, создаете ли вы для UNICODE или нет. % s также изменяется значение,% hs всегда для однобайтовых строк. –

ответ

10

Я ожидаю, что ваш код будет работать - и он работает здесь, в Linux, но он зависит от языка. Это означает, что вам нужно настроить локаль, и ваш язык должен поддерживать набор символов. Вот моя тестовая программа:

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

int main() 
{ 
    int c; 
    char* l = setlocale(LC_ALL, ""); 
    if (l == NULL) { 
     printf("Locale not set\n"); 
    } else { 
     printf("Locale set to %s\n", l); 
    } 
    printf("%ls\n", L"s:\\яшертыHello"); 
    return 0; 
} 

и здесь казнь след:

$ env LC_ALL=en_US.utf8 ./a.out 
Locale set to en_US.utf8 
s:\яшертыHello 

Если он говорит, что язык не установлен или установлен в «C», это нормально, что вы не получите ожидаемого результата.

Редактировать: см. Ответы на this question для эквивалента en_US.utf8 для Windows.

+0

Хмм. Этот ответ кажется правильным видом. Интересно, как вы установили свой язык в utf8, хотя ... когда я пытаюсь это сделать, setlocale терпит неудачу. Документы здесь: http://msdn.microsoft.com/en-us/library/x99tb11d.aspx (если вы ищете utf-8) говорит, что он потерпит неудачу, если вы попробуете utf-8. Возможно, это просто не работает в реализации Microsoft. –

+0

@ScottLangham, имена локали не стандартизированы, и я не знаю, что поддерживается в Windows, но я был бы удивлен, если бы у них не было Unicode - не обязательно UTF8 - locale. – AProgrammer

+1

Windows не поддерживает локализацию Unicode. Во всех реализациях кодировка wchar_t не зависит от локали, поэтому кодировка локали относится только к кодировке узкого символа. Таким образом, для локали Unicode по существу требуется UTF-8, а Windows не предоставляет никаких локалей, использующих UTF-8. Windows поддерживает Unicode, используя UTF-16 в качестве кодировки wchar_t. – bames53

5

В C++ я обычно использую std::stringstream для создания форматированного текста. Я также осуществил собственный оператор, чтобы использовать функцию Windows, чтобы сделать кодировку:

ostream & operator << (ostream &os, const wchar_t * str) 
{ 
    if ((str == 0) || (str[0] == L'\0')) 
    return os; 
    int new_size = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, NULL, NULL, NULL); 
    if (new_size <= 0) 
    return os; 
    std::vector<char> buffer(new_size); 
    if (WideCharToMultiByte(CP_UTF8, 0, str, -1, &buffer[0], new_size, NULL, NULL) > 0) 
    os << &buffer[0]; 
    return os; 
} 

Этот код преобразовать в UTF-8. Для других возможностей проверьте: WideCharToMultiByte.

+0

Хороший пример того, как это сделать :) – jcoder

+0

@JohnB: спасибо! :) – Naszta

Смежные вопросы