Как выйти из utf-8 и преобразовать код utf-8 в байты - PullRequest
0 голосов
/ 19 апреля 2019

Мне нужно преобразовать строку (char []) в строку с экранированием Юникода (в формате: \ u0105).Я пишу код Unicode для преобразования строки из файла примера:

"ąćżźóÓŻŹĆĄŚś ƐƑ Ё" "=>" \ u0105 \ u0107 \ u017C \ u017A \ u00F3 \ u00D3 \ u017B \ u0179 \ u0106 \ u015A \ u015B\ u0190 \ u0181 \ u0182 \ u0401 \ u0402 ".

Теперь мне нужно написать в обратном порядке, например:" \ u0105 "=>" ą "(char [] = {0xC4, 0x85}).

Как это сделать (используя только C)?
Допустим, у меня есть код utf-8 в uint32_t code = 0x0105;

Вот мой код для преобразования строки в escape-кодировку Unicode:

static const uint32_t unicode[48] = {
    0x0000, 0x0040, 0x0080, 0x00C0, 0x0100, 0x0140, 0x0180, 0x01C0, 0x0200, 0x0240, 0x0280, 0x02C0, 0x0300, 0x0340, 0x0380, 0x03C0, 
    0x0400, 0x0440, 0x0480, 0x04C0, 0x0500, 0x0540, 0x0580, 0x05C0, 0x0600, 0x0640, 0x0680, 0x06C0, 0x0700, 0x0740, 0x0780, 0x07C0, 
    0x0800, 0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000, 0x8000, 0x9000, 0xA000, 0xB000, 0xC000, 0xD000, 0xE000, 0xF000, 
};

...

    FILE* fh = fopen("utf.txt", "r");
    char* result;
    char* tmpMemoryBuffer;
    size_t currentSize = 255, currentIndex = 0;
    result = (char*) malloc(sizeof(char) * currentSize);
    memset(result, 0, sizeof(char) * currentSize);


    if (fh != NULL)
    {
        uint8_t c2, c = (uint8_t) getc(fh);
        uint32_t tmp = 0;

        while (c != EOF && c != 0xFF)
        {
            if ((currentIndex - 1) == currentSize)
            {
                tmpMemoryBuffer = (char*) malloc(sizeof(char) * currentSize);
                memcpy(tmpMemoryBuffer, result, sizeof(char) * currentSize);
                result = (char*) realloc(result, sizeof(char) * (currentSize + 255));
                memcpy(result, tmpMemoryBuffer, sizeof(char) * currentSize);
                currentSize += 255;
            }

            if (c >= 0x20 && c <= 0x7E)
            {
                //Is normal char
                printf("Normal:\t%c\n", c);
                result[currentIndex++] = (char) c;
            }
            else if (c >= 0xC0 && c <= 0xEF && (c2 = (uint8_t) getc(fh)) != EOF)
            {
                //Is unicode
                c &= 0x3F;
                c2 &= 0x7F;
                tmp = unicode[c];
                tmp += c2;
                sprintf(result + currentIndex, "\\u%04X", tmp);
                currentIndex += 6;
                printf("Unicode:\t%04X\n", tmp);

            }
            else
            {
                printf("Wrong format for 0x%X\n", c);
                break;
            }
            c = (uint8_t) getc(fh);
        }

        result[currentIndex] = '\0';
        fclose(fh);
...
        free(result);     

Есть ли лучший способ сделать это?

1 Ответ

0 голосов
/ 19 апреля 2019

Если кто-то будет искать, я напишу это как продолжение рассматриваемого кода:

char result[] = "\u0105\u0107\u017C\u017A\u00F3";

char* resultStr = (char*)malloc(sizeof(char) * currentIndex + 1);
size_t reIndex = 0;

for (size_t i = 0; i < strlen(result); i++) 
{
    if (result[i] == '\\')
    {
        if (result[i + 1] != '\0')
        {
            i++;
            switch (result[i])
            {
                case 'u':
                    if (result[i + 1] != '\0' && result[i + 2] != '\0' && result[i + 3] != '\0' && result[i + 4] != '\0')
                    {
                        const char hexstring[5] = {result[i + 1], result[i + 2], result[i + 3], result[i + 4], '\0'};
                        uint32_t code = (uint32_t)strtol(hexstring, NULL, 16);
                        printf ("Code = 0x%X\n", code);
                        uint8_t firstByte = 47;
                        uint8_t secondByte = 0;

                        for (size_t i = 1; i < 48; i++)
                        {
                            if (unicode[i] > code)
                            {
                                firstByte = i - 1;
                                secondByte = (uint8_t)(code - unicode[i - 1]);
                                break;
                            }
                        }

                        firstByte |= 0xC0;
                        secondByte |= 0x80;
                        resultStr[reIndex++] = (char)firstByte;
                        resultStr[reIndex++] = (char)secondByte;
                        i += 4;
                    }
                break;
            }
        }
        else
        {
            //Error
        }
    }
    else
    {
        resultStr[reIndex++] = result[i];
    }
}

resultStr[reIndex] = '\0';
printf("Result = %s\n", resultStr);

Это требует рефакторинга и добавления некоторых функций, таких как дескриптор '\ n', '\ t ',' \ r ', но легкий и быстрый.

У кого-нибудь есть идеи получше?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...