1

UTF-8 でエンコードされたデータを取得して UPNP 経由で表示する組み込みシステムがあります。表示装置には、文字を表示する機能があります。UPNP 経由で受信した UTF-8 データを Unicode に変換する方法が必要です。ディスプレイは PIC 上にあり、Linux を実行している UPNP ブリッジ経由でデータが送信されます。Linuxでディスプレイボードに送信する前に変換を行う簡単な方法はありますか?

4

3 に答える 3

1

UFT-8 としてエンコードされたバイト配列を Unicode コード ポイントの配列に変換するには、次のようにします。

その秘訣は、さまざまなエンコードの誤りを検出することです。

#include <limits.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>

typedef struct {
  uint32_t UnicodePoint;  // Accumulated code point
  uint32_t Min;           // Minimum acceptable codepoint
  int i;                  // Index of char/wchar_t remaining
  bool e;                 // Error flag
} UTF_T;

static bool IsSurrogate(unsigned c) {
  return (c >= 0xD800) && (c <= 0xDFFF);
}

// Return true if more bytes needed to complete codepoint
static bool Put8(UTF_T *U, unsigned ch) {
  ch &= 0xFF;
  if (U->i == 0) {
    if (ch <= 0x7F) {
      U->UnicodePoint = ch;
      return false; /* No more needed */
    } else if (ch <= 0xBF) {
      goto fail;
    } else if (ch <= 0xDF) {
      U->Min = 0x80;
      U->UnicodePoint = ch & 0x1F;
      U->i = 1;
    } else if (ch <= 0xEF) {
      U->Min = 0x800;
      U->UnicodePoint = ch & 0x0F;
      U->i = 2;
    } else if (ch <= 0xF7) {
      U->Min = 0x10000;
      U->UnicodePoint = ch & 0x07;
      U->i = 3;
    } else {
      goto fail;
    }
    return true; /* More needed */
  }
  // If expected continuation character missing ...
  if ((ch & (~0x3F)) != 0x80) {
    goto fail;
  }
  U->UnicodePoint <<= 6;
  U->UnicodePoint |= (ch & 0x3F);
  // If last continuation character ...
  if (--(U->i) == 0) {
    // If codepoint out of range ...
    if ((U->UnicodePoint < U->Min) || (U->UnicodePoint > 0x10FFFF) 
        || IsSurrogate(U->UnicodePoint)) {
      goto fail;
    }
    return false /* No more needed */;
  }
  return true; /* More needed */

  fail:
  U->UnicodePoint = -1;
  U->i = 0;
  U->e = true;
  return false /* No more needed */;
}

/* return 0:OK, else error */
bool ConvertUTF8toUnicodeCodepoints(const char *UTF8, size_t Length, 
    uint32_t *CodePoints, size_t *OutLen) {
  UTF_T U = { 0 };
  *OutLen = 0;
  for (size_t i = 0; i < Length;) {
    while (Put8(&U, UTF8[i++])) {
      // Needed bytes not available?
      if (i >= Length) {
        return true;
      }
    }
    if (U.e) break;
    CodePoints[(*OutLen)++] = U.UnicodePoint;
  }
  return U.e;
}

これはいくつかの古いコードに基づいています。現在の基準に達していない可能性があるため、アドバイスしてください。と魔法の数字
で最もきれいではありません。goto

このアプローチの優れている点は、コードポイントを消費することではなく、CodePoints[(*OutLen)++] = U.UnicodePointUTF16 (BE または LE) を抽出したい場合、ブロックのコンシューマ コードを簡単に記述できUTF_T、UTF8 -> コードポイント部分に変更する必要がないことです。

于 2013-11-11T22:53:23.557 に答える
1

実際のオペレーティング システムとホストされた C 環境を自由に使用できる場合、最善の方法は、UTF-8 をエンコーディングとして使用するロケールでプログラムが実行されるようにするmbrtowcmbtowc、UTF-8 シーケンスを Unicode コードポイントに変換することです。値 (wchar_tは、Linux および を定義する C 実装では Unicode コードポイント番号です__STDC_ISO_10646__)。

システム ライブラリ ルーチンをスキップして UTF-8 デコードを自分で行いたい場合は、注意してください。私はかつて、Google コード検索を使用してカジュアルな調査を行ったことがあり、世の中に出回っている UTF-8 コードの 3 分の 1 から 3 分の 2 の間のどこかが危険なほど間違っていることがわかりました。これは、私が強くお勧めする完全に正しく、高速で、シンプルな実装です。

http://bjoern.hoehrmann.de/utf-8/decoder/dfa/

Musl での私の実装は、バイナリ サイズがやや小さく、高速に見えますが、理解するのも少し難しくなります。

于 2013-11-12T04:01:25.280 に答える
0

LGPL ライセンスのユーティリティ ライブラリである GLibのUnicode 操作関数を使用します。g_utf8_to_ucs4 ()が探しているもののようです。

于 2013-11-12T14:07:51.470 に答える