Win32APIには御存知の通りWideCharToMultiByte
関数とMultiByteToWideChar
関数があるが、わりと使うのは面倒くさい。
そもそも当たり前だけどstd::basic_string<char_type>
使えないし。
というわけでメモ代わりにまとめておく。locale周りはガバのプーさんだけどそこは勘弁して下さい。
結論
これでいいかと。なんとなくshrink_to_fit
呼んでるけどこれ必要なのかねぇ
#include <string>
#include <windows.h>
#include <cstring>
std::wstring shift_jis_to_utf_16(const std::string& str)
{
static_assert(sizeof(wchar_t) == 2, "this function is windows only");
const int len = ::MultiByteToWideChar(932/*CP_ACP*/, 0, str.c_str(), -1, nullptr, 0);
std::wstring re(len * 2 + 2, L'\0');
if (!::MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, &re[0], len)) {
const auto ec = ::GetLastError();
switch (ec)
{
case ERROR_INSUFFICIENT_BUFFER:
throw std::runtime_error("in function utf_16_to_shift_jis, WideCharToMultiByte fail. cause: ERROR_INSUFFICIENT_BUFFER"); break;
case ERROR_INVALID_FLAGS:
throw std::runtime_error("in function utf_16_to_shift_jis, WideCharToMultiByte fail. cause: ERROR_INVALID_FLAGS"); break;
case ERROR_INVALID_PARAMETER:
throw std::runtime_error("in function utf_16_to_shift_jis, WideCharToMultiByte fail. cause: ERROR_INVALID_PARAMETER"); break;
case ERROR_NO_UNICODE_TRANSLATION:
throw std::runtime_error("in function utf_16_to_shift_jis, WideCharToMultiByte fail. cause: ERROR_NO_UNICODE_TRANSLATION"); break;
default:
throw std::runtime_error("in function utf_16_to_shift_jis, WideCharToMultiByte fail. cause: unknown(" + std::to_string(ec) + ')'); break;
}
}
const std::size_t real_len = std::wcslen(re.c_str());
re.resize(real_len);
re.shrink_to_fit();
return re;
}
std::string utf_16_to_shift_jis(const std::wstring& str) {
static_assert(sizeof(wchar_t) == 2, "this function is windows only");
const int len = ::WideCharToMultiByte(932/*CP_ACP*/, 0, str.c_str(), -1, nullptr, 0, nullptr, nullptr);
std::string re(len * 2, '\0');
if (!::WideCharToMultiByte(CP_ACP, 0, str.c_str(), -1, &re[0], len, nullptr, nullptr)) {
const auto ec = ::GetLastError();
switch (ec)
{
case ERROR_INSUFFICIENT_BUFFER:
throw std::runtime_error("in function utf_16_to_shift_jis, WideCharToMultiByte fail. cause: ERROR_INSUFFICIENT_BUFFER"); break;
case ERROR_INVALID_FLAGS:
throw std::runtime_error("in function utf_16_to_shift_jis, WideCharToMultiByte fail. cause: ERROR_INVALID_FLAGS"); break;
case ERROR_INVALID_PARAMETER:
throw std::runtime_error("in function utf_16_to_shift_jis, WideCharToMultiByte fail. cause: ERROR_INVALID_PARAMETER"); break;
default:
throw std::runtime_error("in function utf_16_to_shift_jis, WideCharToMultiByte fail. cause: unknown(" + std::to_string(ec) + ')'); break;
}
}
const std::size_t real_len = std::strlen(re.c_str());
re.resize(real_len);
re.shrink_to_fit();
return re;
}
雑記
CP_ACP
ってところを変えればいろいろ出来たりする。例えばISO_8859_1
なら西ヨーロッパ言語 - iso-8859-1からutf-16への変換ができる。
cf.)
- https://channel9.msdn.com/Forums/TechOff/184894-WIN32-Text-Encoding-APIs/ebf597d0472b441e819e9dea013dba85
- https://msdn.microsoft.com/ja-jp/library/aa288104%28v=vs.71%29.aspx
あと、WideCharToMultiByte関数は第二引数にWC_NO_BEST_FIT_CHARS
を指定せずに呼ぶと似た文字への変換が発生するらしい。
cf.)
- http://d.hatena.ne.jp/hasegawayosuke/20060209#1139475064
- https://msdn.microsoft.com/ja-jp/library/windows/desktop/dd374130%28v=vs.85%29.aspx
参考サイト
- 文字列取得バッファとしてのstd::string - yohhoyの日記
- Visual C++でShift-JISをUTF-8に変換するコード - 今日もスミマセン。
- 備忘録: C++で文字コード変換
追記
ちょっと違うけど
http://qiita.com/AsladaGSX/items/af50066dbbfd59991af9
なんかすごい頑張っている記事を見つけました、