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

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

新規登録して質問してみよう
ただいま回答率
85.50%
Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

Windows

Windowsは、マイクロソフト社が開発したオペレーティングシステムです。当初は、MS-DOSに変わるOSとして開発されました。 GUIを採用し、主にインテル系のCPUを搭載したコンピューターで動作します。Windows系OSのシェアは、90%を超えるといわれています。 パソコン用以外に、POSシステムやスマートフォンなどの携帯端末用、サーバ用のOSもあります。

C++

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

Q&A

解決済

1回答

9346閲覧

C++17でUTF-8Nのファイルを出力したい

退会済みユーザー

退会済みユーザー

総合スコア0

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

Windows

Windowsは、マイクロソフト社が開発したオペレーティングシステムです。当初は、MS-DOSに変わるOSとして開発されました。 GUIを採用し、主にインテル系のCPUを搭載したコンピューターで動作します。Windows系OSのシェアは、90%を超えるといわれています。 パソコン用以外に、POSシステムやスマートフォンなどの携帯端末用、サーバ用のOSもあります。

C++

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

0グッド

1クリップ

投稿2018/05/24 01:23

編集2018/05/24 01:46

質問

C++17でUTF-8(BOMなし)のファイルを出力したいです。

試したこと1

このプログラムの場合0バイトのout.txtが作成されました。

cpp

1#include <iostream> 2#include <string> 3#include <fstream> 4 5int main() { 6 std::wofstream ofs("out.txt"); 7 ofs << L"あいうえお" << std::endl; 8 ofs.close(); 9}

試したこと2

このプログラムで問題なく出力できましたが警告が出ています。警告をなくしたいです。

また、#define _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNINGまたは
#define _SILENCE_ALL_CXX17_DEPRECATION_WARNINGSすると警告は出ませんができれば他の方法で解決したいです。

cpp

1#include <iostream> 2#include <vector> 3#include <string> 4#include <fstream> 5#include <codecvt> 6 7int main() { 8 std::wofstream ofs("out.txt"); 9 // C4996 warning STL4017 10 ofs.imbue(std::locale(std::locale(), new std::codecvt_utf8<wchar_t>)); 11 12 ofs << L"あいうえお" << std::endl; 13 14 ofs.close(); 15}

試したこと3

WideCharToMultiByte を使用する方法として、以下の記事を参考にして作成しましたが、16バイト目に無駄なNULL(0x00)が含まれていました。
http://nekko1119.hatenablog.com/entry/2017/01/02/054629


※out.txtがプログラムで作成したテキストファイル。out2.txtがテキストエディタを使いUTF-8(BOMなし)で「あいうえお」という文字列を書き込んだファイル。

cpp

1#include <Windows.h> 2 3#include <iostream> 4#include <vector> 5#include <string> 6#include <fstream> 7 8std::string wide_to_utf8_winapi(std::wstring const& src) 9{ 10 auto const dest_size = ::WideCharToMultiByte(CP_UTF8, 0U, src.data(), -1, nullptr, 0, nullptr, nullptr); 11 std::vector<char> dest(dest_size, '\0'); 12 if (::WideCharToMultiByte(CP_UTF8, 0U, src.data(), -1, dest.data(), dest.size(), nullptr, nullptr) == 0) { 13 throw std::system_error{ static_cast<int>(::GetLastError()), std::system_category() }; 14 } 15 return std::string(dest.begin(), dest.end()); 16} 17 18int main() { 19 std::ofstream ofs("out.txt"); 20 21 ofs << wide_to_utf8_winapi(L"あいうえお") << std::endl; 22 23 ofs.close(); 24}

環境

OSWindows 10 64bit 1709
IDEVisual Studio 2017
Windows SDK Version10.0.17134.0
文字セットUnicode 文字セットを使用する
PlatformToolSetVisual Studio 2017 (v141)
C++言語標準ISO C++17 Standard (/std:c++17)

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

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

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

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

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

guest

回答1

0

ベストアンサー

普通に

cpp

1#include<fstream> 2 3int main() 4{ 5 std::ofstream ofs("out.txt"); 6 ofs << u8"ありきたり" << std::endl; 7}

でいけなかったっけか。


しかし、固定文字列ではなく

あー、そりゃそうだ。失礼、どうも寝ぼけていたようで。

WideCharToMultiByte を使用する方法として、以下の記事を参考にして作成しましたが、16バイト目に無駄なNULL(0x00)が含まれていました。

まずUTF-8なbyte列で「ありうえお」を表現すると

E3 81 82 E3 81 84 E3 81 86 E3 81 88 E3 81 8A

のようになります。

ここで

out2.txtがテキストエディタを使いUTF-8(BOMなし)で「あいうえお」という文字列を書き込んだファイル。

の出力と見比べると

0D 0A

が余計についている事がわかりますが、これは言うまでもなくCR+LFですね(改行コード)。

out.txtがプログラムで作成したテキストファイル。

の出力のこれも``std::endl`からきているものですね。

さて、NULL文字が含まれる原因はwide_to_utf8_winapiの実装がだめだからです。

修正版がこちらです。

cpp

1#include <string> 2#include <windows.h> 3#include <fstream> 4#include <system_error> 5std::string utf_16_to_utf_8(const std::wstring& str) { 6 static_assert(sizeof(wchar_t) == 2, "this function is windows only"); 7 const int len = ::WideCharToMultiByte(CP_UTF8, 0, str.c_str(), -1, nullptr, 0, nullptr, nullptr); 8 std::string re(len * 2, '\0'); 9 if (!::WideCharToMultiByte(CP_UTF8, 0, str.c_str(), -1, &re[0], len, nullptr, nullptr)) { 10 const auto er = ::GetLastError(); 11 throw std::system_error(std::error_code(er, std::system_category()), "WideCharToMultiByte:(" + std::to_string(er) + ')'); 12 } 13 const std::size_t real_len = std::char_traits<char>::length(re.c_str()); 14 re.resize(real_len); 15 re.shrink_to_fit(); 16 return re; 17} 18int main() { 19 std::ofstream ofs("out.txt"); 20 21 ofs << utf_16_to_utf_8(L"あいうえお") << std::endl; 22}

投稿2018/05/24 02:40

編集2018/05/24 03:17
yumetodo

総合スコア5850

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

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

退会済みユーザー

退会済みユーザー

2018/05/24 02:47

ご回答有り難うございます。 書いていただいたプログラムは期待する結果が得られました。 しかし、固定文字列ではなく変数の場合はどのように書けば良いでしょうか。 以下のように書いた場合 u8str という変数名を指定している事になる為コンパイルエラーとなります。 int main() { std::ofstream ofs("out.txt"); auto str = L"あいうえお"; ofs << u8str << std::endl; } 質問内容が適切でなく申し訳ありません。
退会済みユーザー

退会済みユーザー

2018/05/24 04:14

ありがとうございます。 期待する結果を得ることが出来ました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問