-1

Mac OS X でサーバーからクライアント (C++) へのファイル名の受信に問題があります。シリアル化されたオブジェクトを送信します。このオブジェクトには、ファイル名または場合によっては文字列オブジェクトを含む char ポインターがあります。クライアントで受信すると、%F6 または %E9 の文字が含まれているようです。ただし、同じコードであっても、この問題は Windows OS では発生しません。これらの '%' 文字をデコードして、Mac OS および Linux で元の形式に戻す方法はありますか?

私が問題に陥ったいくつかのキャラクター:

ああああああ

サーバー内のコードを変更するのは難しいので、文字をデコードして元の形式に戻す方法があれば簡単です。

4

1 に答える 1

2

文字は、ISO 8859-1 または同様の 1 バイト コード セットを想定して URL エンコードされているようです。"%F6"簡単な答えは、に変換する必要があるということです'\xF6'。つまり、パーセントと 2 つの 16 進数を対応する 1 バイトに変換する必要があります。

ファイル名は通常、ISO 8859-1 などではなく UTF-8 で保存されるため、Mac OS X では問題が残ります。たとえば (私のプロンプトは「Osiris JL:」です):

Osiris JL: mkdir x
Osiris JL: cd x
Osiris JL: cp /dev/null é
Osiris JL: cp /dev/null è
Osiris JL: ls | odx
0x0000: 65 CC 80 0A 65 CC 81 0A                           e...e...
0x0008:
Osiris JL: ls
è  é
Osiris JL: ls | cat
è
é
Osiris JL: ls | utf8-unicode
(standard input):
0x65 = U+0065
0xCC 0x80 = U+0300
0x0A = U+000A
0x65 = U+0065
0xCC 0x81 = U+0301
0x0A = U+000A
Osiris JL: 

Unicode 文字は、U+0065 LATIN SMALL LETTER E と U+0300 COMBINING GRAVE ACCENT または U+0301 COMBINING ACUTE ACCENT です。

これは、文字 é と è の通常の形成ではありません。多くの場合、U+00E9 LATIN SMALL LETTER E WITH ACUTE および U+00E8 LATIN SMALL LETTER E WITH GRAVE として扱われます。

\xF6は UTF-8 テキストではまったく有効なバイトではありませんが、ISO 8859-1、ISO 8859-15 (および Windows CP1252) では、0xF6 は ö、U+00F6 LATIN SMALL LETTER O WITH DIAERESIS です。

Mac OS X でのファイル作成例

x.c以下は、GCC 4.7.1 でコンパイルされた、Mac OS X 10.7.5 で実行されるいくつかのファイル — source file を作成するプログラムです。

#include <dirent.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

static void create_file(const char *name)
{
    int fd = open(name, O_CREAT|O_TRUNC|O_RDWR, 0644);
    if (fd >= 0)
    {
        close(fd);
        printf("Created file %s OK\n", name);
    }
    else
    {
        printf("Failed to create file %s\n", name);
    }
}

static void print_name(const char *name)
{
    size_t len = strlen(name);
    printf("%-10s = ", name);
    for (size_t i = 0; i < len; i++)
        printf(" %.2X", (unsigned char)name[i]);
    putchar('\n');
}

int main(void)
{
    const char *names[] =
    {
        "a-e\xCC\x80",  /* a-e\u0300 */
        "a-e\xCC\x81",  /* a-e\u0301 */
        "b-\xC3\xA8",   /* b-\u00E8  */
        "b-\xC3\xA9",   /* b-\u00E9  */
        "c-\xF6",
        "c-\xE9",
    };
    enum { NUM_NAMES = sizeof(names) / sizeof(names[0]) };

    for (int i = 0; i < NUM_NAMES; i++)
        create_file(names[i]);

    DIR *dp = opendir(".");
    if (dp != 0)
    {
        struct dirent *entry;
        while ((entry = readdir(dp)) != 0)
            print_name(entry->d_name);
        closedir(dp);
    }
    else
        fprintf(stderr, "error: failed to open current directory\n");

    return(0);
}

これは、アキュート アクセントまたはグレーブ アクセント付きのラテン小文字 'e' の 2 つのエンコーディングを使用します。

正常に実行されますが、ファイル名文字列で U+00E8 または U+00E9 を使用して指定されている場合でも、ファイル名が結合アクセントを使用するように正規化されていることがわかります。

Osiris JL: ls
è       é       makefile x        x.c
Osiris JL: ./x
Created file a-è OK
Created file a-é OK
Created file b-è OK
Created file b-é OK
Created file c-? OK
Created file c-? OK
.          =  2E
..         =  2E 2E
a-è      =  61 2D 65 CC 80
a-é      =  61 2D 65 CC 81
b-è      =  62 2D 65 CC 80
b-é      =  62 2D 65 CC 81
c-%E9      =  63 2D 25 45 39
c-%F6      =  63 2D 25 46 36
è        =  65 CC 80
é        =  65 CC 81
makefile   =  6D 61 6B 65 66 69 6C 65
x          =  78
x.c        =  78 2E 63
Osiris JL: ls
a-è     a-é     b-è     b-é     c-%E9    c-%F6    è       é       makefile x        x.c
Osiris JL: ls | utf8-unicode
(standard input):
0x61 = U+0061
0x2D = U+002D
0x65 = U+0065
0xCC 0x80 = U+0300
0x0A = U+000A
0x61 = U+0061
0x2D = U+002D
0x65 = U+0065
0xCC 0x81 = U+0301
0x0A = U+000A
0x62 = U+0062
0x2D = U+002D
0x65 = U+0065
0xCC 0x80 = U+0300
0x0A = U+000A
0x62 = U+0062
0x2D = U+002D
0x65 = U+0065
0xCC 0x81 = U+0301
0x0A = U+000A
0x63 = U+0063
0x2D = U+002D
0x25 = U+0025
0x45 = U+0045
0x39 = U+0039
0x0A = U+000A
0x63 = U+0063
0x2D = U+002D
0x25 = U+0025
0x46 = U+0046
0x36 = U+0036
0x0A = U+000A
0x65 = U+0065
0xCC 0x80 = U+0300
0x0A = U+000A
0x65 = U+0065
0xCC 0x81 = U+0301
0x0A = U+000A
0x6D = U+006D
0x61 = U+0061
0x6B = U+006B
0x65 = U+0065
0x66 = U+0066
0x69 = U+0069
0x6C = U+006C
0x65 = U+0065
0x0A = U+000A
0x78 = U+0078
0x0A = U+000A
0x78 = U+0078
0x2E = U+002E
0x63 = U+0063
0x0A = U+000A
Osiris JL: 

これは、LATIN SMALL LETTER E WITH GRAVE を含むファイルを作成するプログラムで、文字 è に 2 つの可能なスペルがあることを意味します。

=標識のずれなど、プログラムの出力についてさまざまな興味深い観察結果があります。ただし、重要な点は、名前に無効な UTF-8 文字シーケンスを含むファイル名を作成すると、各無効なバイトは、無効なバイトに対応する 16 進値の%xx場所にURL エンコードされることです (これはディスク上で 3 バイトを占めますが、 xx1、AFAICT)。

概要

Mac OS X で 0x80..0xFF の範囲のバイトを適切な Unicode 文字に正確に変換できるように、ソース文字セットを決定する必要があります。ファイル システムはファイル名を正規化します%F6ö、有効な UTF-8 名を指定する必要があります。

于 2013-01-06T21:57:12.327 に答える