色々とやりようはあるしそこらじゅうに転がってるんですがとりあえず自分が納得するものを作ります。
std::wstring towstring(const char* c) { std::wstring tmps; if (c == nullptr) return tmps; size_t sz = strlen(c); tmps.reserve(sz);//メモリを確保し、newが走りすぎないようにする const size_t CNT_MAX = 50; char tmpc[CNT_MAX]; wchar_t tmpw[CNT_MAX]; const char* p = c; assert(p); while (*p != '\0') { int L = mblen(p, CNT_MAX);//pが指し示すマルチバイト文字のバイト数を取得 if (L <= 0) break; strncpy(tmpc, p, L);//tmpcにその一文字をコピーする tmpc[L] = '\0';
//multi byte string to wide char string mbstowcs(tmpw, tmpc, CNT_MAX);//tmpcの終端を0にしてあるので人文字だけ変換する tmps += tmpw; p += L; } return tmps; } std::string tostring(const wchar_t* c) { std::string tmps; if (c == nullptr) return tmps; size_t sz = wcslen(c); tmps.reserve(sz*2);//メモリを確保し、newが走りすぎないようにする const size_t CNT_MAX = 50; char tmpc[CNT_MAX]; wchar_t tmpw[CNT_MAX]; const wchar_t* p = c; while (*p) {
//サロゲートペアなら2文字分、違うなら1文字分だけtmpwに確保 if (IS_HIGH_SURROGATE(*p) == true) { wcsncpy(tmpw, p, 2); tmpw[2] = L'\0'; p += 2; } else { wcsncpy(tmpw, p, 1); tmpw[1] = L'\0'; p += 1; } wcstombs(tmpc, tmpw, CNT_MAX);//tmpwの内容を変換してtmpcに代入 tmps += tmpc; } return tmps; }
使う時はsetlocaleが必要です。
setlocale(LC_ALL, "");//必要 const char *c = "こんにちは"; std::wstring s = towstring(c);
ここで、 IS_HIGH_SURROGATEはWindowsのマクロです。
IS_HIGH_SURROGATE macro (winnls.h) | Microsoft Docs
定義は、WinNls.hの中で、
#define IS_HIGH_SURROGATE(wch) (((wch) >= HIGH_SURROGATE_START) && ((wch) <= HIGH_SURROGATE_END))
#define IS_LOW_SURROGATE(wch) (((wch) >= LOW_SURROGATE_START) && ((wch) <= LOW_SURROGATE_END))
#define IS_SURROGATE_PAIR(hs, ls) (IS_HIGH_SURROGATE(hs) && IS_LOW_SURROGATE(ls))
こんな感じで定義されています。 なお、
#define HIGH_SURROGATE_START 0xd800 #define HIGH_SURROGATE_END 0xdbff #define LOW_SURROGATE_START 0xdc00 #define LOW_SURROGATE_END 0xdfff
stringが指す先のマルチバイト文字のバイト数を返す。
例えば、 'a' なら1 , 'あ'なら2
他所を参照(手抜き)
mblen | Programming Place Plus C言語編 標準ライブラリのリファレンス
スレッドセーフではない。スレッドセーフであってほしいときはmbrlenを使う
マルチバイト文字列をワイド文字列に変換する。mbs to wcs。
他所を参照
mbstowcs | Programming Place Plus C言語編 標準ライブラリのリファレンス
ワイド 文字列を マルチバイト 文字列に変換する。 wcs to mbs。