2012-11-15 28 views
6

Tôi đang gặp sự cố khi viết ký tự tiếng Pháp cho bảng điều khiển trong C++. Chuỗi được tải từ một tệp bằng cách sử dụng std::ifstreamstd::getline và sau đó được in ra bảng điều khiển bằng cách sử dụng std::cout. Dưới đây là những gì chuỗi trong tệp:Làm thế nào để in các ký tự La tinh sang giao diện điều khiển C++ đúng trên Windows?

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

Và đây là cách chuỗi đang được in:

La Chane qui tương ứng au mã "TEST_CODE" n'a pas Utu trouvÚe Ó l'aide locale "fr".

Làm cách nào để khắc phục sự cố này?

+0

Tôi cho rằng bạn đang sử dụng Windows? –

+0

Có, tôi sẽ sửa đổi câu hỏi của tôi để chỉ định. – jmegaffin

+0

@Boreal: Đảm bảo rằng bạn chuyển đổi chuỗi được lưu trữ trong tệp thành Unicode UTF-16 (có nghĩa là mã hóa Unicode sẽ được sử dụng bên trong ứng dụng Windows). Bạn có thể làm điều đó đọc chuỗi từ tệp của bạn và sau đó sử dụng 'MultiByteToWideChar()' API (hoặc trình trợ giúp chuyển đổi ATL 'CA2W') để chuyển đổi từ mã hóa cụ thể sang UTF-16. Sau đó, để in một chuỗi Unicode thành bàn điều khiển, bạn chỉ cần khởi tạo giao diện điều khiển bằng '_setmode (_fileno (stdout), _O_U16TEXT);', và sau đó bạn có thể sử dụng 'wprintf()' hoặc 'std :: wcout'. Xem câu trả lời của tôi để biết thêm chi tiết và liên kết. –

Trả lời

5

Vấn đề là bảng điều khiển sử dụng các trang mã khác với phần còn lại của hệ thống. Ví dụ, các hệ thống Windows thông thường được thiết lập cho châu Mỹ và Tây Âu sử dụng CP1252, nhưng bàn điều khiển ở những khu vực đó sử dụng CP437 hoặc CP850.

Bạn có thể đặt trang mã đầu ra của bảng điều khiển để khớp với mã hóa bạn đang sử dụng hoặc bạn có thể chuyển đổi các chuỗi để khớp với trang mã đầu ra của bảng điều khiển.

Đặt bảng mã điều khiển đầu ra:

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

Hoặc là một trong nhiều cách để chuyển đổi giữa các bảng mã (cái này đòi hỏi VS2010 hoặc cao hơn):

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

Ví dụ thứ hai giả định bạn làm trong thực tế cần phải chuyển đổi giữa 1252 và 850. Bạn có thể sử dụng hàm GetOEMCP() để tìm ra trang mã đích thực tế và mã nguồn thực sự phụ thuộc vào những gì bạn sử dụng cho mã nguồn thay vì kết quả của GetACP() trên máy chạy chương trình.

Cũng lưu ý rằng chương trình này dựa vào một thứ không được đảm bảo bởi tiêu chuẩn: mã hóa wchar_t được chia sẻ giữa các ngôn ngữ. Điều này đúng trên hầu hết các nền tảng — thường là một số mã hóa Unicode được sử dụng cho wchar_t ở tất cả các ngôn ngữ — nhưng không phải tất cả.


Lý tưởng nhất là bạn chỉ có thể sử dụng UTF-8 ở khắp mọi nơi và sau đây sẽ làm việc tốt, vì nó hiện trên các nền tảng khác những ngày này:

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

Đáng tiếc là Windows không thể hỗ trợ UTF-8 theo cách này mà không phải từ bỏ UTF-16 như mã hóa wchar_t và áp dụng một byte 4 byte, hoặc vi phạm các yêu cầu của tiêu chuẩn và phá vỡ các chương trình phù hợp tiêu chuẩn.

+0

Khi bạn nói đặt trang mã đầu ra của bảng điều khiển, tôi sẽ làm như thế nào? – jmegaffin

+0

@Boreal, sử dụng lệnh 'chcp' để hiển thị trang mã hiện tại hoặc để đặt nó thành một thứ khác. –

+0

Tôi đồng ý với câu trả lời này về nguyên tắc, nhưng các trang mã dường như không khớp. Tôi không thể tìm thấy một kết hợp đồng ý với đầu vào và đầu ra mẫu. –

1

Nếu bạn muốn viết các ký tự Unicode trong giao diện điều khiển, bạn phải làm một số khởi:

_setmode(_fileno(stdout), _O_U16TEXT); 

Sau đó, nhân vật người Pháp của bạn được hiển thị một cách chính xác (tôi đã thử nghiệm nó bằng cách sử Consolas như phông chữ console của tôi):

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

xem xét đọc bài đăng trên blog sau Michael Kaplan:

Hơn nữa, nếu bạn đang đọc một số văn bản từ một tập tin, bạn cần phải biết được mã hóa được sử dụng: UTF-8? UTF-16LE? UTF-16BE? Một số trang mã cụ thể? Sau đó, bạn có thể chuyển đổi từ mã hóa cụ thể sang Unicode UTF-16 và sử dụng UTF-16 bên trong một ứng dụng Windows. Để chuyển đổi từ một số trang mã (hoặc từ UTF-8) sang UTF-16, bạn có thể sử dụng MultiByteToWideChar() API hoặc ATL conversion helper class CA2W.

Các vấn đề liên quan