読者です 読者をやめる 読者になる 読者になる

ICU による文字コード変換ライブラリ

C++文字コードを変換するプログラムを作成したので紹介します.以下に実装する関数 encode を用いれば std::string, std::wstring 間で文字コードを変換できます.
文字コードの変換には代表的なライブラリとして libiconv と ICU とありますが,主にライセンス上の理由により今回は ICU を用います.
ICU による文字コード変換ついては「ICU 2.x : UnicodeString による文字コード変換」に非常に丁寧にまとめられているので,内部の動きについて知りたい方は是非ご覧下さい.
それでは以下に私の実装を示します.

encode.hpp

#ifndef ENCODE_HPP_20100822
#define ENCODE_HPP_20100822

#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif


#include <string>


namespace string {
    // multibyte to widechar
    void         encode(const std::string& codepage, const std::string& src, std::wstring& dst);
    std::wstring encode(const std::string& codepage, const std::string& src);

    // widechar to multibyte
    void         encode(const std::wstring& src, const std::string& codepage, std::string& dst);
    std::string  encode(const std::wstring& src, const std::string& codepage);

    // multibyte to multibyte
    void         encode(const std::string& codepageSrc, const std::string& src, const std::string& codepageDst, std::string& dst);
    std::string  encode(const std::string& codepageSrc, const std::string& src, const std::string& codepageDst);
}


#endif

encode.cpp

#include "encode.hpp"
#include <unicode/ucnv.h>
#include <vector>


// multibyte to widechar
void string::encode(const std::string& codepage, const std::string& src, std::wstring& dst)
{
    const icu::UnicodeString ustr(src.c_str(), src.size(), codepage.c_str());

    dst.assign(ustr.getBuffer(), ustr.getBuffer() + ustr.length());
}


std::wstring string::encode(const std::string& codepage, const std::string& src)
{
    std::wstring dst;

    encode(codepage, src, dst);

    return dst;
}


// widechar to multibyte
void string::encode(const std::wstring& src, const std::string& codepage, std::string& dst)
{
    const icu::UnicodeString ustr(src.c_str(), src.size());
    const int32_t            len = ustr.extract(0, ustr.length(), 0, codepage.c_str());

    if (len > 0) {
        std::vector<char> buf(len);

        ustr.extract(0, ustr.length(), &buf[0], buf.size(), codepage.c_str());
        dst.assign(buf.begin(), buf.end());
    }
    else {
        dst.clear();
    }
}


std::string string::encode(const std::wstring& src, const std::string& codepage)
{
    std::string dst;

    encode(src, codepage, dst);

    return dst;
}


// multibyte to multibyte
void string::encode(const std::string& codepageSrc, const std::string& src, const std::string& codepageDst, std::string& dst)
{
    std::wstring intermediate;

    encode(codepageSrc, src, intermediate);
    encode(intermediate, codepageDst, dst);
}


std::string string::encode(const std::string& codepageSrc, const std::string& src, const std::string& codepageDst)
{
    std::string dst;

    encode(codepageSrc, src, codepageDst, dst);

    return dst;
}

encode.cpp に文字コードを変換する関数 encode を実装しました.encode.cpp をプロジェクトに加え(他のソースコードと一緒にコンパイル),encode.hpp を include することにより encode が使用可能になります.
以下のテストコードで encode の動作を確認できます.

test.cpp

#include "encode.hpp"
#include <locale>
#include <iostream>

#pragma comment(lib, "icuuc.lib")


int main()
{
    std::wcout.imbue(std::locale("japanese"));

    // multibyte to widechar
    std::wcout << string::encode("shift_jis", "テスト") << std::endl; // shift_jis to utf16
    std::wcout << string::encode("euc-jp", "\xA5\xC6\xA5\xB9\xA5\xC8") << std::endl; // euc-jp to utf16
    std::wcout << string::encode("utf8", "\xE3\x83\x86\xE3\x82\xB9\xE3\x83\x88") << std::endl; // utf8 to utf16

    // widechar to multibyte
    std::cout << string::encode(L"テスト", "shift_jis") << std::endl; // utf16 to shift_jis

    // multibyte to multibyte
    std::cout << string::encode("utf8", "\xE3\x83\x86\xE3\x82\xB9\xE3\x83\x88", "shift_jis") << std::endl; // utf8 to shift_jis

    return 0;
}

以上です.
非常に単純な実装ですが,お役に立てると幸いです.