UTF8なstring入れたらShiftJISなstring出てくる関数作った

投稿者: | 2014年11月2日

こんにちは、Sayahamittです。

 

Macで書いていたC++コードをWindows VC++に持ってきたら文字コードでハマったのでメモしておきます。

 

今回は引数にUTF8エンコードのstd::string型文字列を取り、ShiftJISエンコードのstd::string文字列を返す関数と、その逆をやる関数を作りました。

バリバリのWindows API依存コードです。ごめんなさいm(__)m

 

Windowsでは内部的な処理にはUnicodeが使われているにも関わらず、コンソールにおける入出力を始めAPIなど、ユーザーとのインターフェースには未だにShift-JISが使われているようで、UTF8など多バイト文字を直接利用出来ません。

WindowsAPIなんて殆ど触ったことがない自分も、もれなくこの問題に引っかかりました。

Win API を利用する場合にはMultiByteToWideCharメソッドとWideCharToMultiByteメソッドを用いてUTF8とShiftJISの相互変換が実現できるようです。

 

まず、上記の両メソッドを利用する場合は

1.一度変換元文字列を1バイト文字の文字列として読み込んで、それをUnicodeな多バイト文字型に変換

2.Unicodeな多バイト文字列をShiftJISに変換

という手順が必要なようです。

自分は当初、変換表のようなものを使って一発で変換できると思っていたので少し戸惑いました。

特に変換元がUTF8場合に、なんでMultiByteToWideCharを先に使うのか理解できなくて大分悩んでしまった…(´・ω・`)

 

何はともあれ、大事なのはコードですコード。

MultiByteToWideCharメソッドとWideCharToMultiByteメソッドの詳しい説明はMSDNのページを参照して下さい。(自分にはチンプンカンプンで何も分からん)

以下、取り敢えず動いたコード。

 

UTF-8 → Shift-JIS 変換

#include <Windows.h>
std::string UTF8toSjis(std::string srcUTF8){
	//Unicodeへ変換後の文字列長を得る
	int lenghtUnicode = MultiByteToWideChar(CP_UTF8, 0, srcUTF8.c_str(),srcUTF8.size() + 1, NULL, 0);

	//必要な分だけUnicode文字列のバッファを確保
	wchar_t* bufUnicode = new wchar_t[lenghtUnicode];

	//UTF8からUnicodeへ変換
	MultiByteToWideChar(CP_UTF8, 0, srcUTF8.c_str(), srcUTF8.size() + 1,bufUnicode, lenghtUnicode);

	//ShiftJISへ変換後の文字列長を得る
	int lengthSJis = WideCharToMultiByte(CP_THREAD_ACP, 0, bufUnicode, -1, NULL, 0, NULL, NULL);

	//必要な分だけShiftJIS文字列のバッファを確保
	char* bufShiftJis = new char[lengthSJis];

	//UnicodeからShiftJISへ変換
	WideCharToMultiByte(CP_THREAD_ACP, 0, bufUnicode, lenghtUnicode + 1, bufShiftJis, lengthSJis, NULL, NULL);

	std::string strSJis(bufShiftJis);

	delete bufUnicode;
	delete bufShiftJis;

	return strSJis;
}

 

Shift-JIS → UTF-8 変換

#include <Windows.h>
std::string SjistoUTF8(std::string srcSjis){
	//Unicodeへ変換後の文字列長を得る
	int lenghtUnicode = MultiByteToWideChar(CP_THREAD_ACP, 0, srcSjis.c_str(), srcSjis.size() + 1, NULL, 0);

	//必要な分だけUnicode文字列のバッファを確保
	wchar_t* bufUnicode = new wchar_t[lenghtUnicode];

	//ShiftJISからUnicodeへ変換
	MultiByteToWideChar(CP_THREAD_ACP, 0, srcSjis.c_str(), srcSjis.size() + 1, bufUnicode, lenghtUnicode);


	//UTF8へ変換後の文字列長を得る
	int lengthUTF8 = WideCharToMultiByte(CP_UTF8, 0, bufUnicode, -1, NULL, 0, NULL, NULL);

	//必要な分だけUTF8文字列のバッファを確保
	char* bufUTF8 = new char[lengthUTF8];

	//UnicodeからUTF8へ変換
	WideCharToMultiByte(CP_UTF8, 0, bufUnicode, lenghtUnicode + 1, bufUTF8, lengthUTF8, NULL, NULL);

	std::string strUTF8(bufUTF8);

	delete bufUnicode;
	delete bufUTF8;

	return strUTF8;
}

 

相互変換の両者の違いは、UTF8に関連する文字列とShiftJISに関連する文字列が丸っと全部入れ替わるだけです。

 

上記のコードは以下のサイトを丸パクr参考にさせて頂きました。

SOFTIST – ShiftJisとUTF8間のコード変換(VC++)

UserfulCode.net – ユニコード文字列から非ユニコード(SHIFT-JIS)文字列に変換する

UTF8なstring入れたらShiftJISなstring出てくる関数作った」への3件のフィードバック

  1. passerby

    エンコードの変更につまずいていたので助かりました。
    ただ、memory leakがあります:
    delete bufUnicode;
    delete bufUTF8;
    一番最初の char 一個分しかfreeしてません。

    safer:
    delete [] bufUnicode;
    ====
    あと、問題は起きてないみたいですが:
    WideCharToMultiByte(CP_UTF8, 0, bufUnicode, lenghtUnicode + 1, bufUTF8, lengthUTF8, NULL, NULL);

    lenghtUnicode + 1はbufUnicodenobufferのsizeを超えています。
    -1かlengthUnicodeが(仕様書が正しければ)お勧めです。
    まあ、lengthUTF8が書き込みに対するガードをしてるかが読み込みを止めてるようなので、問題無いようですが。

    返信
    1. 傘地蔵

      デストラクタを呼ばないので [] 無しでも同じではないですか。

      返信
  2. 勝田哲司

    末尾に文字化けが出るのですが、
    //必要な分だけUTF8文字列のバッファを確保
    char* bufUTF8 = new char[lengthUTF8];
    memset(bufUTF8,0,lengthUTF8);
    みたいな感じにしたら文字化けが無くなりました。

    返信

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください