5

UTF-16を生のUnicodeコードポイントにデコードするUnicodeライブラリの一部があります。ただし、期待どおりに機能していません。

コードの関連部分は次のとおりです(UTF-8と文字列操作のものを省略):

typedef struct string {
    unsigned long length;
    unsigned *data;
} string;

string *upush(string *s, unsigned c) {
    if (!s->length) s->data = (unsigned *) malloc((s->length = 1) * sizeof(unsigned));
    else            s->data = (unsigned *) realloc(s->data, ++s->length * sizeof(unsigned));
    s->data[s->length - 1] = c;
    return s;
}

typedef struct string16 {
    unsigned long length;
    unsigned short *data;
} string16;

string u16tou(string16 old) {
    unsigned long i, cur = 0, need = 0;
    string new;
    new.length = 0;
    for (i = 0; i < old.length; i++)
        if (old.data[i] < 0xd800 || old.data[i] > 0xdfff) upush(&new, old.data[i]);
        else
            if (old.data[i] > 0xdbff && !need) {
                cur = 0; continue;
            } else if (old.data[i] < 0xdc00) {
                need = 1;
                cur = (old.data[i] & 0x3ff) << 10;
                printf("cur 1: %lx\n", cur);
            } else if (old.data[i] > 0xdbff) {
                cur |= old.data[i] & 0x3ff;
                upush(&new, cur);
                printf("cur 2: %lx\n", cur);
                cur = need = 0;
            }
    return new;
}

それはどのように機能しますか?

stringは32ビット値を保持する構造体であり、string16UTF-16のような16ビット値用です。必要に応じupushて、完全なUnicodeコードポイントをstringメモリに再割り当てするだけです。

u16tou私が焦点を当てている部分です。をループし、string16通常どおり非サロゲート値を渡し、サロゲートペアを完全なコードポイントに変換します。置き忘れた代理人は無視されます。

ペアの最初のサロゲートでは、下位10ビットが左に10ビットシフトされ、最終的なコードポイントの上位10ビットが形成されます。もう一方のサロゲートでは、最下位10ビットがファイナルに追加されてから、文字列に追加されます。

問題?

最高のコードポイントを試してみましょう。

U+10FFFD、最後の有効なUnicodeコードポイントは0xDBFF 0xDFFD、UTF-16のようにエンコードされます。それをデコードしてみましょう。

string16 b;
b.length = 2;
b.data = (unsigned short *) malloc(2 * sizeof(unsigned short));
b.data[0] = 0xdbff;
b.data[1] = 0xdffd;
string a = u16tou(b);
puts(utoc(a));

(表示されてutocいません。動作していることはわかっています(以下を参照))関数を使用してchar *、印刷用にUTF-8に変換し直すと、結果U+0FFFFDではなく、取得していることが端末で確認できますU+10FFFD

電卓で

gcalctoolですべての変換を手動で実行すると、同じ間違った答えが返されます。したがって、私の構文自体は間違っていませんが、アルゴリズムは間違っています。アルゴリズムは私には正しいように思えますが、それでも間違った答えで終わっています。

私は何が間違っているのですか?

4

2 に答える 2

5

サロゲートペアをデコードするときは、0x10000を追加する必要があります。rfc 2781を引用すると、欠落しているステップは5番目です。

    1)W1<0xD800またはW1>0xDFFFの場合、文字値Uは値です。
       W1の。終了します。

    2)W1が0xD800と0xDBFFの間にあるかどうかを判別します。そうでない場合、シーケンス
       はエラーであり、W1を使用して有効な文字を取得できません。
       終了します。

    3)W2がない場合(つまり、シーケンスがW1で終了する場合)、またはW2の場合
       0xDC00と0xDFFFの間にない場合、シーケンスにエラーがあります。
       終了します。

    4)20ビットの符号なし整数U'を作成し、下位10個を取得します。
       W1のビットを上位10ビットおよび下位10ビットとして
       その10の下位ビットとしてのW2。

    5)U'に0x10000を追加して、文字値Uを取得します。終了します。

すなわち。1つの修正は、最初に読んだ後に行を追加することです。

cur = (old.data[i] & 0x3ff) << 10;
cur += 0x10000;
于 2010-09-24T13:18:03.107 に答える
0

のオフセットが欠落しているようです0x10000

このWIKIページによると、UTF-16サロゲートペアは次のように構成されています。

UTF-16は、サロゲートペアと呼ばれる2つのコードユニットを使用して、非BMP文字(U+10000からU+10FFFF)を表します。最初の10000016 コードポイントから減算され、20ビット値が得られます。次に、これは2つの10ビット値に分割され、それぞれがサロゲートとして表され、最も重要な半分が最初のサロゲートに配置されます。

于 2010-09-24T13:43:51.280 に答える