2012-11-15 4 views
6

У меня возникла проблема с написанием французских символов на консоли в C++. Строка загружается из файла с использованием std::ifstream и std::getline, а затем печатается на консоль с использованием std::cout. Вот то, что строка в файле:Как правильно печатать латинские буквы на консоли C++ в Windows?

La Chaîne Квай соответствуют помощница код «TEST_CODE» n'a па été à l'trouvée помощник локаль «фр».

А вот как строка печатается:

La Чейн Квай соответствуют а.е. код "TEST_CODE" n'a па Уту trouvÚe РГУ l'помощник локали "FR".

Как исправить эту проблему?

+0

Предполагаю, что вы используете Windows? –

+0

Да, я изменю свой вопрос, чтобы указать. – jmegaffin

+0

@Boreal: убедитесь, что вы преобразовали строку, хранящуюся в файле, в Unicode UTF-16 (что имеет смысл в кодировке Unicode для использования в приложении Windows). Вы можете сделать это, прочитав строку из вашего файла, а затем используя API 'MultiByteToWideChar()' (или вспомогательный конвертер ATL 'CA2W') для преобразования из вашей конкретной кодировки в UTF-16. Затем, чтобы напечатать строку Unicode для консоли, вам просто нужно инициализировать консоль с помощью '_setmode (_fileno (stdout), _O_U16TEXT);' и затем вы можете использовать 'wprintf()' или 'std :: wcout'. См. Мой ответ для получения дополнительной информации и ссылок. –

ответ

5

Проблема в том, что консоль использует разные кодовые страницы, чем остальная часть системы. Например, обычные системы Windows, созданные для Северной и Южной Америки и Западной Европы, используют CP1252, но консоль в этих регионах использует CP437 или CP850.

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

Установить консольный вывод кодовая:

SetConsoleOutputCP(GetACP()); // GetACP() returns the system codepage. 
std::cout << "La chaîne qui correspond au code \"TEST_CODE\" n'a pas été trouvée à l'aide locale \"fr\"."; 

Или один из многих способов преобразования между кодировками (это одна требует VS2010 или выше):

#include <codecvt> // for wstring_convert 
#include <locale> // for codecvt_byname 
#include <iostream> 

int main() { 
    typedef std::codecvt_byname<wchar_t,char,std::mbstate_t> codecvt; 

    // the following relies on non-standard behavior, codecvt destructors are supposed to be protected and unusable here, but VC++ doesn't complain. 
    std::wstring_convert<codecvt> cp1252(new codecvt(".1252")); 
    std::wstring_convert<codecvt> cp850(new codecvt(".850")); 

    std::cout << cp850.to_bytes(cp1252.from_bytes("...été trouvée à...\n")).c_str(); 
} 

Последний пример предполагает, что вы делаете на самом деле необходимо преобразовать между 1252 и 850. Вероятно, вы должны использовать функцию GetOEMCP(), чтобы определить фактическую страницу целевого кода, а исходная кодовая страница на самом деле зависит от того, что вы используете для исходного кода, а не от результата GetACP() машина, запускающая программу.

Также обратите внимание, что эта программа зависит от того, что не гарантируется стандартом: чтобы кодировка wchar_t была разделена между локалями. Это справедливо на большинстве платформ —, как правило, некоторые кодировки Unicode используются для wchar_t во всех локалях —, но не для всех.


В идеале вы могли бы просто использовать UTF-8 везде и следующий будет работать нормально, как это делает на других платформах эти дни:

#include <iostream> 

int main() { 
    std::cout << "La chaîne qui correspond au code \"TEST_CODE\" n'a pas été trouvée à l'aide locale \"fr\".\n"; 
} 

К сожалению для Windows не поддерживает UTF-8 таким образом, без отказа от UTF-16 в качестве кодировки wchar_t и принятия 4-байтового wchar_t или нарушения требований стандарта и стандартного соответствия стандартным программам.

+0

Когда вы говорите, задаете страницу выходного кода консоли, как бы я это сделал? – jmegaffin

+0

@Boreal, используйте команду 'chcp', чтобы отобразить текущую страницу кода или установить ее на что-то еще. –

+0

Я согласен с этим ответом в принципе, но кодовые страницы, похоже, не совпадают. Я не могу найти комбинацию, которая согласуется с образцом ввода и вывода. –

1

Если вы хотите писать символы Unicode в консоли, вы должны сделать некоторые инициализации:

_setmode(_fileno(stdout), _O_U16TEXT); 

Тогда ваши французские символы отображаются правильно (я проверил его с помощью Consolas в моей консоли шрифта):

#include <fcntl.h> 
#include <io.h> 

#include <iostream> 
#include <ostream> 
#include <string> 

using namespace std; 

int main() 
{ 
    // Prepare console output in Unicode 
    _setmode(_fileno(stdout), _O_U16TEXT); 


    // 
    // Build Unicode UTF-16 string with French characters 
    // 

    // 0x00EE - LATIN SMALL LETTER I WITH CIRCUMFLEX 
    // 0x00E9 - LATIN SMALL LETTER E WITH ACUTE 
    // 0x00E0 - LATIN SMALL LETTER A WITH GRAVE 

    wstring str(L"La cha"); 
    str += L'\x00EE'; 
    str += L"ne qui correspond au code \"TEST_CODE\" "; 
    str += L"n'a pas "; 
    str += L'\x00E9'; 
    str += L't'; 
    str += L'\x00E9'; 
    str += L" trouv"; 
    str += L'\x00E9'; 
    str += L"e "; 
    str += L'\x00E0'; 
    str += L" l'aide locale \"fr\"."; 


    // Print the string to the console 
    wcout << str << endl; 
} 

Вы можете прочитать следующие сообщения пользователя Michael Kaplan:

Кроме того, если вы читаете текст из файла, вы должны знать, какие кодирование используется: UTF-8? UTF-16LE? UTF-16BE? Некоторая конкретная страница кода? Затем вы можете конвертировать из определенной кодировки в Unicode UTF-16 и использовать UTF-16 в приложении Windows. Для преобразования с некоторой кодовой страницы (или из UTF-8) в UTF-16 вы можете использовать MultiByteToWideChar() API или ATL conversion helper class CA2W.