2016-12-12 19 views
6

Nếu bạn nạp một giá trị số wchar_t, char16_t hoặc char32_t vào một luồng hẹp, nó sẽ in giá trị số của điểm mã.iostreams - In giá trị `wchar_t` hoặc` charXX_t` thành một ký tự

#include <iostream> 
using std::cout; 
int main() 
{ 
    cout << 'x' << L'x' << u'x' << U'x' << '\n'; 
} 

in x120120120. Điều này là do có một số operator<< cho sự kết hợp cụ thể của basic_ostream với số charT, nhưng không có toán tử tương tự cho các loại ký tự khác, vì vậy chúng được chuyển thành âm thầm thành int và được in theo cách đó. Tương tự, xâu phi hẹp (L"x", u"x", U"X") sẽ được âm thầm chuyển đổi sang void* và in như giá trị con trỏ, và không hẹp chuỗi đối tượng (wstring, u16string, u32string) thậm chí sẽ không biên dịch.

Vì vậy, câu hỏi: cách khủng khiếp nhất để in một, char16_t, hoặc giá trị wchar_tchar32_t trên ostream hẹp, như nhân vật, chứ không phải là giá trị số của điểm mã là gì? Nó phải chuyển đổi một cách chính xác tất cả các điểm mã hóa có thể thể hiện được trong mã hóa của ostream, tới mã hóa đó và sẽ báo cáo lỗi khi điểm mã hóa không thể biểu diễn được. (Ví dụ, được đưa ra u'…' và một dòng chảy UTF-8, chuỗi ba byte 0xE2 0x80 0xA6 phải được ghi vào luồng; nhưng được đưa ra u'â' và một dòng KOI8-R, một lỗi nên được báo cáo.)

Tương tự , làm thế nào có thể in một chuỗi C-string hoặc đối tượng chuỗi không hẹp trên một ostream hẹp, chuyển đổi sang mã hóa đầu ra?

Nếu không thể thực hiện việc này trong ISO C++ 11, tôi sẽ trả lời theo từng nền tảng cụ thể.

(Lấy cảm hứng từ this question.)

+2

Tóm lại, bạn phải 1) sử dụng một dòng rộng hoặc 2) chuyển đổi dữ liệu ký tự rộng sang mã hóa hẹp chính bạn (đó là một chuyển đổi có thể mất). Một ostream không thể thực hiện chuyển đổi đó cho bạn. Xem ['std :: wstring_convert'] (http: //en.cppreference.com/w/cpp/locale/wstring_convert) hoặc sử dụng thư viện như [ICONV] (https://www.gnu.org/software/libiconv/) hoặc [ICU] (http: //site.icu-project. org /). –

Trả lời

2

Như bạn đã nói, không có operator<<(std::ostream&, const wchar_t) cho một ostream hẹp. Tuy nhiên, nếu bạn muốn sử dụng cú pháp, bạn có thể dạy ostream cách thực hiện với wchar s để thói quen đó được chọn là tình trạng quá tải tốt hơn mà trước tiên cần phải chuyển đổi thành số nguyên.

Nếu bạn đang cảm thấy mạo hiểm:

namespace std { 
    ostream& operator<< (ostream& os, wchar_t wc) { 
    if(unsigned(wc) < 256) // or another upper bound 
     return os << (unsigned char)wc; 
    else 
     throw your_favourite_exception; // or handle the error in some other way 
    } 
} 

Nếu không, làm cho một đơn giản struct rằng minh bạch bao gồm một wchar_t và có một tùy chỉnh friend operator<< và chuyển đổi ký tự rộng của bạn để mà trước khi xuất chúng.

Edit: Để thực hiện chuyển đổi on-the-fly đến và đi từ các địa phương, bạn có thể sử dụng các chức năng từ <cwchar>, như:

ostream& operator<< (ostream& os, wchar_t wc) { 
    std::mbstate_t state{}; 
    std::string mb(MB_CUR_MAX, '\0'); 
    size_t ret = std::wcrtomb(&mb[0], wc, &state); 
    if(ret == static_cast<std::size_t>(-1)) 
     deal_with_the_error(); 
    return os << mb; 
} 

Đừng quên để thiết lập miền địa phương của mình vào hệ thống mặc định:

std::locale::global(std::locale("")); 
std::cout << L'ŭ'; 
+0

Điều này không chuyển đổi giá trị sang mã hóa đầu ra hẹp. Đó là điều cần thiết, và nó cũng là phần mà tôi chưa biết làm thế nào để làm. – zwol

+0

@zwol Bạn muốn chuyển đổi một nhân vật rộng hơn là chấp nhận nó như thế nào nếu nó nằm trong ASCII và từ chối khác? Sau đó, bạn cần phải cụ thể, ví dụ: xóa dấu trọng âm hoặc thứ gì đó. –

+0

Ví dụ của bạn sử dụng dấu 'x' để chuyển nó (cho 'L'x'', bạn cần phải làm tương tự cho các loại khác) vì vậy tôi cho rằng đó là những gì bạn đang theo dõi. Ví dụ: –

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