LoginSignup
21
18

More than 5 years have passed since last update.

そろそろWindowsでUTF-16とShift-JISの変換方法をC++erらしくまとめようか

Last updated at Posted at 2016-01-30

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.)

あと、WideCharToMultiByte関数は第二引数にWC_NO_BEST_FIT_CHARSを指定せずに呼ぶと似た文字への変換が発生するらしい。
cf.)

参考サイト

追記

ちょっと違うけど
http://qiita.com/AsladaGSX/items/af50066dbbfd59991af9
なんかすごい頑張っている記事を見つけました、

21
18
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
18