これは Windows では簡単ではありません。Windows コンソールにテキストを取得できたとしても、日本語の文字を表示できるように cmd.exe を構成する必要があります。
#include <iostream>
int main() {
std::cout << "こんにちは世界\n";
}
これは、次のようなシステムで正常に機能します。
- コンパイラのソースおよび実行エンコーディングには、文字が含まれます。
- 出力デバイス (コンソールなど) は、コンパイラの実行エンコーディングと同じエンコーディングのテキストを想定しています。
- 適切な文字を含むフォントが利用可能です (通常は問題ありません)。
最近のほとんどのプラットフォームは、これらすべてのエンコーディングにデフォルトで UTF-8 を使用しているため、上記のようなコードで Unicode 範囲全体をサポートできます。残念ながら、Windows はこれらのプラットフォームの 1 つではありません。
wcout << L"こんにちは世界\n";
この行では、文字列リテラル データが (コンパイル時に) ソース エンコーディングから実行全体のエンコーディングに変換され、(実行時に)wcout
組み込まれているロケールを使用して wchar_t データを出力用の char データに変換します。うまくいかないのは、デフォルトのロケールが基本的なソース文字セットからの文字をサポートすることだけを必要とすることです。これには、非 ASCII 文字は言うまでもなく、すべての ASCII 文字も含まれていません。
したがって、変換はエラーにwcout
なり、悪い状態になります。wcout が再び機能する前に、エラーをクリアする必要があります。これが、2 番目の print ステートメントが何も出力しない理由です。
wcout
文字を正常に変換するロケールを吹き込むことで、限られた範囲の文字でこれを回避できます。残念ながら、この方法で Unicode 範囲全体をサポートするために必要なエンコーディングは UTF-8 です。Microsoft のストリームの実装は他のマルチバイト エンコーディングをサポートしていますが、厳密には UTF-8 をサポートしていません。
例えば:
wcout.imbue(std::locale(std::locale::classic(), new std::codecvt_utf8_utf16<wchar_t>()));
SetConsoleOutputCP(CP_UTF8);
wcout << L"こんにちは世界\n";
ここでwcout
は、文字列を UTF-8 に正しく変換します。出力がコンソールではなくファイルに書き込まれた場合、ファイルには正しい UTF-8 データが含まれます。ただし、Windows コンソールは、ここで UTF-8 データを受け入れるように構成されていても、この方法で記述された UTF-8 データを受け入れません。
いくつかのオプションがあります:
標準ライブラリを完全に回避します。
DWORD n;
WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), L"こんにちは世界\n", 8, &n, nullptr);
標準コードを壊す非標準の魔法の呪文を使用します。
#include <fcntl.h>
#include <io.h>
_setmode(_fileno(stdout), _O_U8TEXT);
std::wcout << L"こんにちは世界\n";
このモードstd::cout << "Hello, World";
を設定するとクラッシュします。
手動変換とともに低レベル IO API を使用します。
#include <codecvt>
#include <locale>
SetConsoleOutputCP(CP_UTF8);
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> convert;
std::puts(convert.to_bytes(L"こんにちは世界\n"));
これらの方法のいずれかを使用すると、cmd.exe はその能力を最大限に発揮して正しいテキストを表示します。つまり、判読できないボックスが表示されます。指定された文字列の 7 つの小さなボックス。
テキストを cmd.exe から notepad.exe などにコピーして、正しいグリフを表示できます。