C++でstring型の文字コードを変換する方法
C++で日本語文字を取り扱ってたら1日が終わった。。
KST32BというストロークフォントをC++から使おうとしてたら色々とハマってしまったという話です。
KST32BはJISコードの文字のストロークフォントを保持してるのだけど、C++のstring型はUTF8の文字コードを取り扱っててどうやってJISコードに変換しようという問題でした。
Windows(Visual C++)の情報は色々出てくるんだけど、Mac(というかLinux)はなかなか情報出てこなかったので苦労しました。
こちらのURLに記載されている通りiconv.hを使えばいけるとのことです。ありがとうございます。
http://bebolog.blogspot.jp/2014/11/c.html
コードはコピペだけど転載いたします。
string convert_encoding(const std::string &str, const char *fromcode, const char *tocode) { char *outstr, *instr; iconv_t icd; size_t instr_len = std::strlen(str.c_str()); size_t outstr_len = instr_len*2; if (instr_len <= 0) return ""; // allocate memory instr = new char[instr_len+1]; outstr = new char[outstr_len+1]; strcpy(instr, str.c_str()); icd = iconv_open(tocode, fromcode); if (icd == (iconv_t)-1) { return "Failed to open iconv (" + std::string(fromcode) + " to " + std::string(tocode) + ")"; } char *src_pos = instr, *dst_pos = outstr; if (iconv(icd, &src_pos, &instr_len, &dst_pos, &outstr_len) == -1) { // return error message std::string errstr; int err = errno; if (err == E2BIG) { errstr = "There is not sufficient room at *outbuf"; } else if (err == EILSEQ) { errstr = "An invalid multibyte sequence has been encountered in the input"; } else if (err = EINVAL) { errstr = "An incomplete multibyte sequence has been encountered in the input"; } iconv_close(icd); return "Failed to convert string (" + errstr + ")"; } *dst_pos = '\0'; iconv_close(icd); std::string s(outstr); delete[] instr; delete[] outstr; return s; }
Xcodeで開発してる場合は、libiconv.dylibをフレームワークに追加した上でiconv.hをインクルードしてください。 使い方は
string conv_str = convert_encoding(str, "utf-8", "euc-jp");
みたいな感じで第2引数に元の文字コード、第3引数に変換したい文字コードを渡してあげればOKです。
実際のJISコードへの変換ですが、こんな感じでやってます。
string convertUTF8ToJIS(const string &str){ string conv_str = convert_encoding(str, "utf-8", "euc-jp"); vector<int> jislist; int c = 0; for(int i=0;i<conv_str.size();i++){ int tmp = conv_str[i]&0x7f; c = c<<8; c += tmp; } stringstream ss; ss<<hex<<c; string jis = ss.str(); if(jis.size() < 4){ int n_zero = 4 - jis.size(); switch (n_zero) { case 1: jis = "0" + jis; break; case 2: jis = "00" + jis; break; case 3: jis = "000" + jis; break; default: break; } } // to Upper transform(jis.begin(), jis.end(), jis.begin(), ::toupper); return jis; }
元々KST32Bを取り扱うpythonコードがあったのでそれを参考にしています。
http://boxheadroom.com/2009/06/03/kst
これでKST32BをC++から使えるようになりました。 KST32Bのストローク解析コードも書いたけど、基本上のpythonコードのC++版です。ニッチすぎるので需要はないと思いますが、欲しければご連絡いただければと思います。