質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Windows 10

Windows 10は、マイクロソフト社がリリースしたOSです。Modern UIを標準画面にした8.1から、10では再びデスクトップ主体に戻され、UIも変更されています。PCやスマホ、タブレットなど様々なデバイスに幅広く対応していることが特徴です。

標準入力

標準入力(stdin)は、プログラムが標準的に用いるデータ入力元。リダイレクトしない限り、プログラムを起動した端末のキーボードが標準入力になります。UNIX系OSやC言語に実装されて普及した概念ですが、他のOSや言語も含めた総称としても使われます。

Visual C++

Microsoft Visual C++はWindowsのCとC++の統合開発環境(IDE)であり、コンパイラやデバッガを含んでいます。

UTF-8

UTF-8は8ビット符号単位の文字符号化形式及び文字符号化スキームです。データ交換方式、ファイル形式としては、一般的にUTF-8が使われる傾向があります。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

2回答

3841閲覧

MSVCにおいて、標準入力からUTF-8の文字列を入力したい

tomolatoon

総合スコア0

Windows 10

Windows 10は、マイクロソフト社がリリースしたOSです。Modern UIを標準画面にした8.1から、10では再びデスクトップ主体に戻され、UIも変更されています。PCやスマホ、タブレットなど様々なデバイスに幅広く対応していることが特徴です。

標準入力

標準入力(stdin)は、プログラムが標準的に用いるデータ入力元。リダイレクトしない限り、プログラムを起動した端末のキーボードが標準入力になります。UNIX系OSやC言語に実装されて普及した概念ですが、他のOSや言語も含めた総称としても使われます。

Visual C++

Microsoft Visual C++はWindowsのCとC++の統合開発環境(IDE)であり、コンパイラやデバッガを含んでいます。

UTF-8

UTF-8は8ビット符号単位の文字符号化形式及び文字符号化スキームです。データ交換方式、ファイル形式としては、一般的にUTF-8が使われる傾向があります。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

1グッド

1クリップ

投稿2021/05/06 09:08

編集2021/05/06 14:53

実現したいこと

MSVCコンソールプログラムで、標準入力からUTF-8エンコードされた文字列を入力したいです。
標準出力であれば、コードページを65001(UTF-8)にすることで対処できることが周知されています。
しかし、入力の場合にはそれでは正しく入力することが出来ませんでした。
どうすれば期待した動作にすることが出来るでしょうか。ご教授の程お願いいたします。
追記:「リダイレクトを使う」という回答を頂きましたが、あくまで標準入力にこだわる解決法もお願いいたします。

環境・前提

Windows 10 20H2
Visual Studio Community 2019 16.9.4
言語標準はC++17(/std:c++17)です。
追加のオプションで/utf-8を指定しています。
Windows 10のシステムロケールをUTF-8にする機能は使用していません。

症状

以下のことを行うコードを用意しました。

  1. cmd.exeのコードページを65001にする
  2. 標準入力からsに入力をする
  3. sの各バイトについて、ビットごとに出力する
  4. sをそのまま標準出力に出力する

cpp

1#include <iostream> 2#include <string> 3#include <bitset> 4 5int main() 6{ 7 system("chcp 65001"); 8 9 std::string s; 10 std::cin >> s; 11 for (auto&& ele : s) { 12 std::cout << " " << std::bitset<8>(ele) << std::endl; 13 } 14 std::cout << s; 15}

実行結果です。aに関しては問題ありませんでした。
しかし、と思われる部分はデタラメかつ1バイトの値で、実行するごとに値が変わります。

cmd

1Active code page: 65001 2aあ 3 01100001 4 00110000 5a0

試したこと

疑ったのはロケールです。CRTの記事ですが、MSVCは".utf8"で、utf8をコードページに出来るようです。
setlocale, _wsetlocale | Microsoft Docs

以下のコードを用い、std::cinのロケールを変更して症状と同じことを行いました。
が、実行結果では症状と同様、の部分がデタラメな1バイトの値になってしまっています。

cpp

1#include <iostream> 2#include <sstream> 3#include <string> 4#include <bitset> 5 6int main() 7{ 8 system("chcp 65001"); 9 10 std::cin.imbue(std::locale(".utf8")); 11 12 std::string s; 13 std::cin >> s; 14 for (auto&& ele : s) { 15 std::cout << " " << std::bitset<8>(ele) << std::endl; 16 } 17 std::cout << s; 18}

cmd

1Active code page: 65001 2aあ 3 01100001 4 11110000 5a

確認したこと

ところがstd::ifstreamstd::istringstreamにおいては、正常に動作することが確認できました。
ですから、std::istreamが壊れていることは考えづらいです。ということは、cmd.exeのUTF-8サポートが完全ではないのでしょうか。

以下のコードと、UTF-8エンコードのファイル(utf8_test.txt、BOMなし)を用意して検証しました。

cpp

1// cmd.cpp 2 3#include <iostream> 4#include <sstream> 5#include <string> 6#include <fstream> 7#include <filesystem> 8 9int main() 10{ 11 system("chcp 65001"); 12 13 std::string s; 14 15 std::ifstream ifs(std::filesystem::path("D:/utf8_test.txt")); 16 ifs >> s; 17 std::cout << s << std::endl; 18 19 std::stringstream ss(u8"aあ"); 20 ss >> s; 21 std::cout << s << std::endl; 22}

txt

1aあ

cmd

1Active code page: 65001 2aあ 3aあ
yumetodo👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dodox86

2021/05/06 15:43

試したことがないので単なる推測ですが、 > Windows 10のシステムロケールをUTF-8にする機能は使用していません。 出力はまだ良いとして、入力はIMEも関わるので、入力(をUTF-8としてコンソールへ反映して出力)はできないのではないでしょうか。
dodox86

2021/05/06 17:12

コマンドプロンプトへのテキストのコピー&ペーストだとIMEを使わず、Windowsのクリップボード経由になると思うけど、クリップボードがUTF-8をサポートできているかというと、さて。
guest

回答2

0

しかし、入力の場合にはそれでは正しく入力することが出来ませんでした。

コンソールに打ち込むのではなく、リダイレクトしてファイルから流し込めばいいのではないでしょうか?

投稿2021/05/06 09:09

maisumakun

総合スコア146018

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tomolatoon

2021/05/06 09:42

素早いご回答ありがとうございます。 リダイレクトする発想は抜け落ちていました…試してしっかりと動作することも確認できました! ただそれだとIDEから実行、終了した際コンソールが消えてしまうので、もし、あくまで標準入力に固執した解決法も御座いましたら教えていただければ幸いです。 (「標準出力もリダイレクトする」や「ブレークポイントを使う」等々でプログラムを一時停止すればいいと言われてしまったらそれまでですが…)
yumetodo

2021/05/06 16:58

私も試してみましたけどやっぱりstd::cin/std::wcinもしくはその裏側のコンソールホストが壊れてますよねこれ。
yumetodo

2021/05/06 16:58

もっと低レベルのコンソールの入力取ってくるWin32APIを探して見る価値があるかもしれない・・・?
Bull

2021/05/06 23:53

ReadConsoleA でもできないようです。ReadConsoleW ならできるのですが。 私もいろいろ探したり試したりしてみたのですが、現状の Windows10 のコンソールで UTF-8 文字列の入力はできないのではないかと考えています。 Microsoft 公式の文書で、できないというのは見ていないので、何らかの方法があるのかもしれませんが。
yumetodo

2021/05/08 00:23

するともうconhost側とかが壊れていそうですね・・・。
Bull

2021/05/08 07:23

私もそのように思っていたのですが、不思議なことに同じコンソール (conhost) を使用している WSL は UTF-8 での入出力が問題なくできます。 完全に憶測ですが、サブシステムの違いによるものと考えています。
yumetodo

2021/05/08 12:16

回答に書いたように、ucrtの問題という説がありますね・・・。
guest

0

うーん、
https://developercommunity.visualstudio.com/t/-read-cannot-read-utf-8-but-cgets-s-can/910961
にあるように、ReadConsoleW のラッパーたる_cgets_sを使うのがワークアラウンドっぽい?
ucrt側のバグという可能性。せめてこの報告されてるissueをupvoteしておきますか・・・

https://github.com/microsoft/terminal/issues/4551#issuecomment-585487802
ReadFile and ReadConsoleA are currently limited to 7-bit ASCII when the input codepage is UTF-8 (65001) due to an assumption of 1 CHAR per WCHAR when calling WideCharToMultiByte.


いやまてよ、そもそもこのバグが治ったとして、どうせ内部でUTF-16->UTF-8変換が挟まるなら、ユーザーランドでやっても変わらなくないか?となるとネタで昔作った
https://github.com/yumetodo/utf8_streambuf
がまさかの出番という可能性・・・。

投稿2021/05/08 00:30

編集2021/05/08 00:40
yumetodo

総合スコア5852

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Bull

2021/05/09 01:55 編集

結局 UTF-8 では入力はできないような予感が ... ReadConsoleW では読み込めるので、それをライブラリで UTF-8 なり、Shift_JIS に変換してくれてもいいのですが、ReadConsoleW ではリダイレクトが効かなかったような。 ああそうか、ライブラリでリダイレクトを判断して、Read/ReadConsoleW を使い分ければいいのか。
yumetodo

2021/05/09 03:51

リダイレクトされているとReadConsoleはコケるはずなのでそのときはstd::cinのstreambufに処理を投げるようなstram bufがあればよさそう。
tomolatoon

2021/05/10 21:52

お時間割いていただきありがとうございます。 現状だとstreambuf作るのが一番そうですね…(´・ω・`)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問