Как напечатать wstring в Linux / OS X?

Как я могу напечатать такую ​​строку: €áa¢cée£ на консоли / экране? Я пробовал это:

#include <iostream>    
#include <string>
using namespace std;

wstring wStr = L"€áa¢cée£";

int main (void)
{
    wcout << wStr << " : " << wStr.length() << endl;
    return 0;
}

который не работает. Даже сбивает с толку, если я удалю из строки, распечатка будет такой: ?a?c?e? : 7 но с в строке, ничего не печатается после символа .

Если я напишу тот же код на Python:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

wStr = u"€áa¢cée£"
print u"%s" % wStr

он правильно распечатывает строку на той же консоли. Чего мне не хватает в c ++ (ну, я просто новичок)? Ваше здоровье!!


Обновление 1: на основе предложения n.m.

#include <iostream>
#include <string>
using namespace std;

string wStr = "€áa¢cée£";
char *pStr = 0;

int main (void)
{
    cout << wStr << " : " << wStr.length() << endl;

    pStr = &wStr[0];
    for (unsigned int i = 0; i < wStr.length(); i++) {
        cout << "char "<< i+1 << " # " << *pStr << " => " << pStr << endl;
        pStr++;
    }
    return 0;
}

Прежде всего, он сообщает 14 как длину строки: €áa¢cée£ : 14 Это потому, что он считает 2 байта на символ?

И все, что я получаю:

char 1 # ? => €áa¢cée£
char 2 # ? => ??áa¢cée£
char 3 # ? => ?áa¢cée£
char 4 # ? => áa¢cée£
char 5 # ? => ?a¢cée£
char 6 # a => a¢cée£
char 7 # ? => ¢cée£
char 8 # ? => ?cée£
char 9 # c => cée£
char 10 # ? => ée£
char 11 # ? => ?e£
char 12 # e => e£
char 13 # ? => £
char 14 # ? => ?

как последний вывод cout. Так что, я считаю, актуальная проблема все еще остается. Ваше здоровье!!


Обновление 2: на основе второго предложения n.m.

#include <iostream>
#include <string>

using namespace std;

wchar_t wStr[] = L"€áa¢cée£";
int iStr = sizeof(wStr) / sizeof(wStr[0]);        // length of the string
wchar_t *pStr = 0;

int main (void)
{
    setlocale (LC_ALL,"");
    wcout << wStr << " : " << iStr << endl;

    pStr = &wStr[0];
    for (int i = 0; i < iStr; i++) {
       wcout << *pStr << " => " <<  static_cast<void*>(pStr) << " => " << pStr << endl;
       pStr++;
    }
    return 0;
}

И вот что я получаю в результате:

€áa¢cée£ : 9
€ => 0x1000010e8 => €áa¢cée£
á => 0x1000010ec => áa¢cée£
a => 0x1000010f0 => a¢cée£
¢ => 0x1000010f4 => ¢cée£
c => 0x1000010f8 => cée£
é => 0x1000010fc => ée£
e => 0x100001100 => e£
£ => 0x100001104 => £
 => 0x100001108 => 

Почему там указано 9, чем 8? Или это то, чего мне стоит ожидать? Ваше здоровье!!


person MacUsers    schedule 23.07.2011    source источник
comment
Какая кодировка вашего файла исходного кода? ASCII?   -  person selalerer    schedule 23.07.2011
comment
Возможный дубликат: stackoverflow.com/questions/331690/c-source-in-unicode   -  person BenjaminB    schedule 23.07.2011
comment
@selalerer: кодировка исходного файла - например, # -*- coding: utf-8 -*- в python? Как мне узнать или установить это в c ++? Я просто использую vim для написания скрипта. Ваше здоровье!!   -  person MacUsers    schedule 23.07.2011
comment
@Mac Каждый исходный файл - это просто текстовый файл. Каждый текстовый файл имеет некоторую кодировку, это может быть что-то, основанное на таблице ASCII (в которой каждый символ - один байт) или UTF-8 или UTF-16 и т. Д. Сегодня каждый текстовый редактор поддерживает сохранение файла, в котором когда-либо кодировалось твой выбор. Как это сделать в vim? stackoverflow .com / questions / 778069 /   -  person selalerer    schedule 23.07.2011
comment
@selalerer: вот что это: uniTest.cpp: UTF-8 Unicode c program text. Я был бы удивлен, если бы это было не так. Vim используется одинаково для всех вещей, в то время как, например, python работает, а c ++ - нет. Чего-то еще вам не хватает? ваше здоровье!   -  person MacUsers    schedule 23.07.2011


Ответы (1)


Отбросьте L перед строковым литералом. Используйте std::string, а не std::wstring.

UPD: Есть лучшее (правильное) решение. сохраните wchar_t, wstring и L и вызовите setlocale(LC_ALL,"") в начале вашей программы.

В любом случае вы должны вызвать setlocale(LC_ALL,"") в начале вашей программы. Это указывает вашей программе работать с локалью вашей среды, а не с локалью по умолчанию "C". В вашей среде используется кодировка UTF-8, поэтому все должно работать.

Без вызова setlocale(LC_ALL,"") программа работает с последовательностями UTF-8, не «осознавая», что они являются UTF-8. Если на терминале напечатана правильная последовательность UTF-8, она будет интерпретирована как UTF-8, и все будет выглядеть нормально. Вот что произойдет, если вы используете string и char: gcc использует UTF-8 в качестве кодировки по умолчанию для строк, и ostream с радостью печатает их, не применяя никакого преобразования. Он думает, что имеет последовательность символов ASCII.

Но когда вы используете wchar_t, все ломается: gcc использует UTF-32, правильная перекодировка не применяется (потому что языковой стандарт - "C"), а вывод - мусор.

Когда вы вызываете setlocale(LC_ALL,""), программа знает, что ей следует перекодировать UTF-32 в UTF-8, и все снова в порядке.

Все это предполагает, что мы хотим работать только с UTF-8. Использование произвольных локалей и кодировок выходит за рамки этого ответа.

person n. 1.8e9-where's-my-share m.    schedule 23.07.2011
comment
УХ ТЫ!! это действительно работает. Это заставляет меня задавать другой вопрос: что на самом деле wstring (а значит, и wchar_t, я думаю) на самом деле для этого? Ваше здоровье!! - person MacUsers; 23.07.2011
comment
wchar_t - расплывчатый тип, достаточно большой, чтобы вместить любой символ из набора символов вашей системы, но что с этим делать - полностью зависит от вашей платформы. Обычно вам необходимо взаимодействовать со средой с помощью функций _2 _ / _ 3_ или %Ls в printf и т. Д. См. Здесь мою небольшую тираду по этому поводу или используйте C ++ 0x для явных строк Unicode. - person Kerrek SB; 23.07.2011
comment
@ n.m .: Что ж, сейчас я не совсем уверен, действительно ли это работает: если я попробую что-то вроде этого: cout << *pStr << " => " << pStr << endl; - он напечатает это: ? => €áa¢cée£ на консоли. pStr - указатель типа char. Я обновил свое исходное сообщение новым измененным скриптом. Ваше здоровье!! - person MacUsers; 23.07.2011
comment
@Kerrek SB: Спасибо за ссылки. C++0x Поддерживается ли какая-либо платформа / ОС? Ваше здоровье!! - person MacUsers; 23.07.2011
comment
C ++ 0x поддерживается GCC 4.3 и выше, а также MSVS2010. Насчет других компиляторов не знаю ... - person Kerrek SB; 23.07.2011
comment
Я отредактировал ответ другим предложением, надеюсь, более правильным, чем предыдущее! Я очень торопился и не успел закончить как следует с первого раза. - person n. 1.8e9-where's-my-share m.; 23.07.2011
comment
@ n.m .: Я получаю: error: expected constructor, destructor, or type conversion before ‘(’ token в строке setlocale (LC_ALL,). Я добавил эту строку сразу после включения заголовков. Я что-то не так делаю? Самое главное, что означает эта ошибка? Ваше здоровье!! - person MacUsers; 23.07.2011
comment
1. Вам нужно включить дополнительный заголовок, #include <locale> 2. Вам нужно вызвать setlocale внутри функции main(). Вы не можете использовать операторы на уровне файла в C ++, там разрешены только объявления. Ошибка немного загадочная. Компилятор попытался интерпретировать оператор как объявление, но отказался на середине. В нем говорится, какой вклад он ожидал в этот момент. - person n. 1.8e9-where's-my-share m.; 23.07.2011
comment
аааа ... теперь я понял. Хотя я уже включил заголовок ‹locale›, на самом деле он у меня работает без него. Это почти сработало, за исключением одной небольшой проблемы: я просто вижу другую проблему: в конец добавляется [пробел], и 9 указывается как длина строки. Почему это происходит? Я обновил свой исходный пост новой модификацией. Ваше здоровье!! - person MacUsers; 23.07.2011
comment
Хм, я не знаю, почему вы получаете 9 и пробел. Я получаю 8 и без пробелов, как и ожидалось. Возможно, у вас странный регион. Что говорит ваша locale команда linux, а также echo $LANG? UPD: Я знаю, почему вы печатаете завершающий символ NULL. Не надо. Используйте std :: wstring для простоты, не используйте массивы и указатели C ++ и строки с завершающим NULL. - person n. 1.8e9-where's-my-share m.; 23.07.2011
comment
Сообщается о en_GB.UTF-8 (как я и ожидал) как для $LANG, так и для всех СРЕДСТВ locale. - person MacUsers; 23.07.2011
comment
Я думаю, мой int iStr расчет неверен. если я изменю его на wstring wStr = L"€áa¢cée£"; и int iStr = wStr.length(); - все работает нормально, как и ожидалось. Ваше здоровье!! - person MacUsers; 23.07.2011