2012-11-15 6 views
6

Mam problem z pisaniem francuskich znaków na konsoli w C++. Ciąg jest ładowany z pliku przy użyciu std::ifstream i std::getline, a następnie drukowany na konsoli przy użyciu std::cout. Oto, co znajduje się w pliku:Jak poprawnie drukować znaki łacińskie na konsoli C++ w systemie Windows?

La chaîne qui odpowiada kodowi au "TEST_CODE" n'a pas été trouvée à l'aide locale "fr".

A oto jak łańcuch jest wydrukowane:

La CHANE qui odpowiadać au kodu "TEST_CODE" n'a pas Utu trouvÚe Ó l'aide locale "FR".

Jak mogę rozwiązać ten problem?

+0

Zakładam, że używasz systemu Windows? –

+0

Tak, zmieniam moje pytanie w celu określenia. – jmegaffin

+0

@Boreal: Upewnij się, że konwertujesz ciąg znaków zapisany w pliku na kod Unicode UTF-16 (co ma sens w przypadku kodowania Unicode w aplikacji Windows). Możesz to zrobić czytając ciąg z twojego pliku, a następnie używając 'MultiByteToWideChar()' API (lub pomocnika konwersji ATL 'CA2W'), aby przekonwertować z twojego konkretnego kodowania do UTF-16. Następnie, aby wydrukować ciąg znaków Unicode do konsoli, wystarczy zainicjować konsolę za pomocą '_setmode (_fileno (standardowe), _O_U16TEXT);', a następnie można użyć 'wprintf()' lub 'std :: wcout'. Zobacz moją odpowiedź na dalsze szczegóły i linki. –

Odpowiedz

5

Problem polega na tym, że konsola korzysta z różnych stron kodowych niż reszta systemu. Na przykład zwykle systemy Windows skonfigurowane dla obu Ameryk i Europy Zachodniej używają CP1252, ale konsola w tych regionach używa CP437 lub CP850.

Możesz ustawić stronę kodową wyjścia konsoli tak, aby pasowała do używanego kodowania lub konwertować ciągi tak, aby pasowały do ​​strony kodowej wyjścia konsoli.

Ustaw kodowa wyjście konsoli:

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\"."; 

Albo jeden z wielu sposobów do konwersji między kodowań (ten wymaga VS2010 lub nowszej):

#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(); 
} 

Ten ostatni przykład zakłada, że ​​w rzeczywistości Konwersja pomiędzy 1252 i 850. Prawdopodobnie powinieneś użyć funkcji GetOEMCP(), aby znaleźć rzeczywistą docelową stronę kodową, a źródłowa strona kodowa zależy od tego, czego używasz dla kodu źródłowego, a nie od wyniku GetACP() na maszyna uruchamiająca program.

Należy również zauważyć, że program ten opiera się na czymś, co nie jest gwarantowane przez standard: kodowanie wchar_t jest współużytkowane pomiędzy ustawieniami regionalnymi. Dotyczy to większości platform — zwykle niektóre kodowanie Unicode jest używane do wchar_t we wszystkich lokalizacjach —, ale nie wszystkie.


Idealnie można po prostu użyć UTF-8 oraz dodaje się wszędzie będzie działać dobrze, jak ma to miejsce na innych platformach te dni:

#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"; 
} 

Niestety Windows nie obsługuje UTF-8 w ten sposób bez porzucania UTF-16 jako kodowania wchar_t i przyjmowania 4 bajtów wchar_t, lub naruszania wymagań standardu i łamania standardowych programów zgodnych.

+0

Kiedy mówisz ustawić wyjściową stronę kodową konsoli, jak mam to zrobić? – jmegaffin

+0

@Boreal, użyj komendy 'chcp', aby wyświetlić bieżącą stronę kodową lub ustawić ją na coś innego. –

+0

Zgadzam się z tą odpowiedzią w zasadzie, ale strony kodowe wydają się nie pasować. Nie mogę znaleźć kombinacji, która zgadza się z przykładowym wejściem i wyjściem. –

1

Jeśli chcesz pisać znaki Unicode w konsoli, trzeba zrobić kilka inicjalizacji:

_setmode(_fileno(stdout), _O_U16TEXT); 

Wtedy twoje francuskie znaki są wyświetlane poprawnie (Przetestowałem go za pomocą Consolas jak mój czcionki konsoli):

#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; 
} 

Rozważmy przeczytaniu następujących blogach autorem jest Michael Kaplan:

Ponadto, jeśli czytasz tekst z pliku, trzeba wiedzieć, które kodowanie jest używane: UTF-8? UTF-16LE? UTF-16BE? Jakaś konkretna strona kodowa? Następnie możesz konwertować dane z kodowania na kodowanie UTF-16 w standardzie Unicode i używać kodowania UTF-16 w aplikacji Windows. Aby przekonwertować z jakiejś strony kodowej (lub z UTF-8) na UTF-16, możesz użyć MultiByteToWideChar() API lub ATL conversion helper class CA2W.

Powiązane problemy