18


8

C ++でUnicode文字列を処理する最適なマルチプラットフォームの方法は何ですか?
StackOverflowには、 `std

string`対` std :: wstring`または類似のものについて既にいくつかの質問があることを知っていますが、完全なソリューションを提案したものはありません。

適切な答えを得るには、要件を定義する必要があります。

  • *マルチプラットフォーム*の使用、Windows、OS XおよびLinuxで動作する必要があります

  • プラットフォーム固有のユニコードへの/からの変換のための最小限の労力 UTF-8の「CFStringRef」、「wchar_t *」、「char *」などの文字列、またはOS APIで必要なその他のタイプ。 注:サポートされているすべてのオペレーティングシステムでUnicode互換機能のみを使用する予定なので、コードページ変換のサポートは必要ありません。

  • 外部ライブラリが必要な場合、これは* open-source *であり、 BSDのような非常に自由なライセンスの下で、LGPLではありません。

  • * printf format *構文などを使用できます。

  • 文字列の割り当て/割り当て解除の簡単な方法

  • ユニコードは 文字列はアプリケーションUIにのみ使用されます。

  • いくつかの例をいただければ幸いです

回答ごとに1つの提案された解決策*のみを本当に感謝するでしょう。 複数の選択肢がある場合は、別の答えを追加してください。

*あなたのために働いた*何かを示してください。

関連する質問

5 Answer


7


アプリケーションの内部でUTF-8を使用し、データストレージに通常の古い `char *`または `std

string`を使用することを強くお勧めします。 異なるエンコード(ASCII、UTF-16など)を使用するAPIとのインターフェースには、LGPLの下でライセンスされているhttp://www.gnu.org/software/libiconv/[libiconv]を使用することをお勧めします。

使用例

class TempWstring
{
public:
  TempWstring(const char *str)
  {
    assert(sUTF8toUTF16 != (iconv_t)-1);
    size_t inBytesLeft = strlen(str);
    size_t outBytesLeft = 2 * (inBytesLeft + 1);  // worst case
    mStr = new char[outBytesLeft];
    char *outBuf = mStr;
    int result = iconv(sUTF8toUTF16, &str, &inBytesLeft, &outBuf, &outBytesLeft);
    assert(result == 0 && inBytesLeft == 0);
  }

  ~TempWstring()
  {
    delete [] mStr;
  }

  const wchar_t *Str() const { return (wchar_t *)mStr; }

  static void Init()
  {
    sUTF8toUTF16 = iconv_open("UTF-16LE", "UTF-8");
    assert(sUTF8toUTF16 != (iconv_t)-1);
  }

  static void Shutdown()
  {
    int err = iconv_close(sUTF8toUTF16);
    assert(err == 0);
  }

private:
  char *mStr;

  static iconv_t sUTF8toUTF16;
};

iconv_t TempWstring::sUTF8toUTF16 = (iconv_t)-1;

// At program startup:
TempWstring::Init();

// At program termination:
TempWstring::Shutdown();

// Now, to convert a UTF-8 string to a UTF-16 string, just do this:
TempWstring x("Entr\xc3\xa9""e");  // "Entrée"
const wchar_t *ws = x.Str();  // valid until x goes out of scope

// A less contrived example:
HWND hwnd = CreateWindowW(L"class name",
                          TempWstring("UTF-8 window title").Str(),
                          dwStyle, x, y, width, height, parent, menu, hInstance, lpParam);


5


Adam Rosenfieldの回答(+1)と同じですが、代わりにhttp://utfcpp.sourceforge.net/[UTFCPP]を使用します。


2


「ワイド文字列はユニコードですか?」という理由で、クロスプラットフォームプロジェクトにstd

wstringを使用することにしたプロジェクトに最近参加しましたこれは多くの頭痛の種につながりました。

  • wstringのスカラー値はどれくらいですか? 回答:それは次第です コンパイラー実装。 Visual Studio(Win)では、16ビットです。 ただし、Xcode(Mac)では32ビットです。

  • これにより、通信にUTF-16を使用するという不幸な決定に至りました。 ワイヤー上。 しかし、どのUTF-16ですか? UTF-16BE(ビッグエンディアン)とUTF16-LE(リトルエンディアン)の2つがあります。 これを明確にしないと、さらに多くのバグにつながります。

プラットフォーム固有のコードを使用している場合、プラットフォームのネイティブ表現を使用してそのAPIと通信することは理にかなっています。 ただし、プラットフォーム間で共有されるコード、またはプラットフォーム間で通信するコードについては、すべてのあいまいさを避け、UTF-8を使用してください。


1


経験則:処理にはネイティブプラットフォームのUnicode形式(UTF-16またはUTF-32)を使用し、データ交換(通信、ストレージ)にはUTF-8を使用します。

すべてのネイティブAPIが(たとえばWindowsで)UTF-16を使用する場合、文字列をUTF-8にすると、すべての入力をUTF-16に変換し、Win APIを呼び出してから、回答をUTF-8に変換する必要があります。 かなりの痛み。

しかし、主な問題がUIである場合、文字列は単純な問題です。 より難しいのはUIフレームワークです。 そのために、wxWidgets(http://www.wxWidgets.org)をお勧めします。 成熟した(17年と非常にアクティブな)多くのプラットフォーム、ネイティブウィジェット、Unicode、リベラルライセンスをサポートします。


1


メモリ内のUTF16表現と、ハードディスクまたはワイヤ上のUTF-8または16を使用します。 主な理由:UTF16には、各「文字」のサイズが固定されています。 これにより、弦の操作時の多くの作業が簡素化されます(部品の消去、交換など)。

UTF-8の唯一の理由は、「western / latin」文字のメモリ使用量の削減です。 この表現は、ディスクストレージまたはネットワーク経由の転送に使用できます。 また、ディスク/ワイヤへのロード/保存時にバイト順を気にする必要がないという利点もあります。

これらの理由を念頭に置いて、内部でstd

wstringを使用するか、またはGUIライブラリがWidestringを提供する場合は、それを使用します(QTのQStringなど)。 また、ディスクストレージについては、プラットフォームAPIのプラットフォームに依存しない小さなラッパーを作成します。 または、この変換に利用できるプラットフォームに依存しないコードがある場合は、unicode.orgをチェックしてください。

'' '' '

明確化のために:韓国語/日本語の文字は西洋/ラテン語ではありません。 日本語は漢字の例です。 それが、ラテン文字セットについて言及した理由です。

'' '' '

UTF-16が1文字/ 2バイトではない場合。 この仮定は、ベースの多言語面にいるキャラクターにのみ当てはまります(http://en.wikipedia.org/wiki/UTF16を参照)。 それでも、UTF-16のほとんどのユーザーは、すべての文字がBMPにあると想定しています。 アプリケーションでこれが保証されない場合は、UTF32に切り替えるかUTF8に切り替えることができます。

まだ多くのAPIで上記の理由でUTF-16が使用されています(例: Windows、QT、Java、.NET、wxWidgets)