मुझे समझ में आता है कि सवाल काफी पुराना है, लेकिन अगर कोई दिलचस्पी लेता है, तो मेरा समाधान नीचे है। मैंने एक बहुत ही सरल std :: streambuf वंशज को लागू किया है और फिर इसे प्रोग्राम निष्पादन की शुरुआत में मानक धाराओं में से प्रत्येक को पास कर दिया है।
यह आपको अपने कार्यक्रम में हर जगह यूटीएफ -8 का उपयोग करने की अनुमति देता है। इनपुट पर, यूनिकोड में कंसोल से डेटा लिया जाता है और फिर परिवर्तित किया जाता है और यूटीएफ -8 में आपके पास वापस आ जाता है। आउटपुट पर विपरीत किया जाता है, यूटीएफ -8 में आपके द्वारा डेटा लेना, इसे यूनिकोड में परिवर्तित करना और कंसोल पर भेजना। अभी तक कोई समस्या नहीं मिली है।
यह भी ध्यान दें कि इस समाधान को SetConsoleCP
, SetConsoleOutputCP
या chcp
, या कुछ और के साथ किसी भी कोडपृष्ठ संशोधन की आवश्यकता नहीं है।
धारा बफर है कि:
class ConsoleStreamBufWin32 : public std::streambuf
{
public:
ConsoleStreamBufWin32(DWORD handleId, bool isInput);
protected:
// std::basic_streambuf
virtual std::streambuf* setbuf(char_type* s, std::streamsize n);
virtual int sync();
virtual int_type underflow();
virtual int_type overflow(int_type c = traits_type::eof());
private:
HANDLE const m_handle;
bool const m_isInput;
std::string m_buffer;
};
ConsoleStreamBufWin32::ConsoleStreamBufWin32(DWORD handleId, bool isInput) :
m_handle(::GetStdHandle(handleId)),
m_isInput(isInput),
m_buffer()
{
if (m_isInput)
{
setg(0, 0, 0);
}
}
std::streambuf* ConsoleStreamBufWin32::setbuf(char_type* /*s*/, std::streamsize /*n*/)
{
return 0;
}
int ConsoleStreamBufWin32::sync()
{
if (m_isInput)
{
::FlushConsoleInputBuffer(m_handle);
setg(0, 0, 0);
}
else
{
if (m_buffer.empty())
{
return 0;
}
std::wstring const wideBuffer = utf8_to_wstring(m_buffer);
DWORD writtenSize;
::WriteConsoleW(m_handle, wideBuffer.c_str(), wideBuffer.size(), &writtenSize, NULL);
}
m_buffer.clear();
return 0;
}
ConsoleStreamBufWin32::int_type ConsoleStreamBufWin32::underflow()
{
if (!m_isInput)
{
return traits_type::eof();
}
if (gptr() >= egptr())
{
wchar_t wideBuffer[128];
DWORD readSize;
if (!::ReadConsoleW(m_handle, wideBuffer, ARRAYSIZE(wideBuffer) - 1, &readSize, NULL))
{
return traits_type::eof();
}
wideBuffer[readSize] = L'\0';
m_buffer = wstring_to_utf8(wideBuffer);
setg(&m_buffer[0], &m_buffer[0], &m_buffer[0] + m_buffer.size());
if (gptr() >= egptr())
{
return traits_type::eof();
}
}
return sgetc();
}
ConsoleStreamBufWin32::int_type ConsoleStreamBufWin32::overflow(int_type c)
{
if (m_isInput)
{
return traits_type::eof();
}
m_buffer += traits_type::to_char_type(c);
return traits_type::not_eof(c);
}
उपयोग तो इस प्रकार है:
template<typename StreamT>
inline void FixStdStream(DWORD handleId, bool isInput, StreamT& stream)
{
if (::GetFileType(::GetStdHandle(handleId)) == FILE_TYPE_CHAR)
{
stream.rdbuf(new ConsoleStreamBufWin32(handleId, isInput));
}
}
// ...
int main()
{
FixStdStream(STD_INPUT_HANDLE, true, std::cin);
FixStdStream(STD_OUTPUT_HANDLE, false, std::cout);
FixStdStream(STD_ERROR_HANDLE, false, std::cerr);
// ...
std::cout << "\xc3\xbc" << std::endl;
// ...
}
बाहर wstring_to_utf8
बाएँ और utf8_to_wstring
आसानी से WideCharToMultiByte
और MultiByteToWideChar
WinAPI कार्यों के साथ लागू किया जा सकता।
मुझे पहले C++ iostreams में परेशानी हुई है। वहां बहुत सारी छिपी हुई नीचता है जो समस्याओं का कारण बनती है। यह एक उत्तर के लायक नहीं है, लेकिन जब iostreams आपको परेशानी देता है, सी के stdio का उपयोग करें, मुझे इस तरह के मुद्दों के साथ कई बार पहले किया था। –
हां, iostreams का उपयोग stdio से अधिक जटिल है, यहां तक कि [पूर्ण लंबाई वाली पाठ्य पुस्तकों] भी हैं (http://www.amazon.com/Standard-Iostreams-Locales-Programmers-Reference/dp/0201183951) इसके बारे में। लेकिन iostreams आपको लचीलापन का एक बड़ा सौदा देता है, जिसे मैं खुशी से उपयोग कर रहा हूं। – mkluwe
क्या यह विंडोज कंसोल की समस्या नहीं है? मुझे याद है कि यह किसी भी तरह से असीमित नहीं है, ऐसी कई समस्याएं पैदा कर रहा है ... –