首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从iso-8859-15 (Latin9)到UTF-8的转换?

从iso-8859-15 (Latin9)到UTF-8的转换?
EN

Stack Overflow用户
提问于 2012-06-29 15:49:08
回答 2查看 4.5K关注 0票数 2

我需要将一些格式为Latin9字符集的字符串转换为UTF-8。我不能使用iconv,因为它没有包含在我的嵌入式系统中。你知道有没有一些可用的代码?

EN

回答 2

Stack Overflow用户

发布于 2012-06-29 19:07:35

1127的代码点在拉丁语-9 (ISO-8859-15)和UTF-8中是相同的。

拉丁语中的代码点164是U+20AC,\xe2\x82\xac = UTF-8中的226 130 172

拉丁语中的代码点166是U+0160,\xc5\xa0 = 197 160中的UTF-8。

拉丁语中的代码点168是U+0161,\xc5\xa1 = 197 161中的UTF-8。

拉丁语中的代码点180是U+017D,\xc5\xbd = 197 189中的UTF-8。

拉丁语中的代码点184是U+017E,\xc5\xbe = 197 190中的UTF-8。

拉丁语-9中的代码点188是U+0152,\xc5\x92 = UTF-8中的197 146

拉丁语中的代码点189是U+0153,\xc5\x93 = UTF-8中的197 147

拉丁语中的代码点190是U+0178,\xc5\xb8 = UTF-8中的197 184

拉丁语中的编码点-9\f25 128 .. 191 -9(除了上面列出的编码点)都映射到-9 \xc2\x80 ..\xc2\xbf = UTF-8格式的194 128 .. 194 191

拉丁语中的代码点192 .. 255都映射到\xc3\x80..\xc3\xbf = UTF-8格式的195 128 .. 195 191

这意味着在UTF-8中,拉丁-9代码点1..127是1字节长,代码点164是3字节长,其余的(128..163和165..255)是2字节长。

如果首先扫描拉丁-9输入字符串,则可以确定生成的UTF-8字符串的长度。如果您愿意或需要--毕竟您是在嵌入式系统上工作--那么您可以通过从头到尾向后工作的方式就地进行转换。

编辑:

这里有两个函数,您可以使用这两种方法进行转换。它们返回一个动态分配的副本,您需要在使用后进行free()。它们只在发生错误(内存不足,errno == ENOMEM)时返回NULL。如果给定要转换的NULL或空字符串,则函数将返回动态分配的空字符串。

换句话说,当你使用完这些函数返回的指针时,你应该总是调用free()。(允许使用free(NULL),但不执行任何操作。)

如果输入不包含零字节,则latin9_to_utf8()已被验证为生成与iconv完全相同的输出。该函数使用标准C字符串,即零字节表示字符串结束。

如果输入只包含同样采用ISO-8859-15的Unicode代码点,并且不包含零字节,则utf8_to_latin9()已经过验证,可以生成与iconv完全相同的输出。当给定随机的UTF-8字符串时,该函数将拉丁语-1中的8个代码点映射到拉丁语-9的等价物,即货币符号到欧元;iconv要么忽略它们,要么考虑这些错误。

utf8_to_latin9()行为意味着函数既适用于Latin 1->UTF-8->Latin 1往返,也适用于Latin 9->UTF-8->Latin9往返。

代码语言:javascript
复制
#include <stdlib.h>     /* for realloc() and free() */
#include <string.h>     /* for memset() */
#include <errno.h>      /* for errno */

/* Create a dynamically allocated copy of string,
 * changing the encoding from ISO-8859-15 to UTF-8.
*/
char *latin9_to_utf8(const char *const string)
{
    char   *result;
    size_t  n = 0;

    if (string) {
        const unsigned char  *s = (const unsigned char *)string;

        while (*s)
            if (*s < 128) {
                s++;
                n += 1;
            } else
            if (*s == 164) {
                s++;
                n += 3;
            } else {
                s++;
                n += 2;
            }
    }

    /* Allocate n+1 (to n+7) bytes for the converted string. */
    result = malloc((n | 7) + 1);
    if (!result) {
        errno = ENOMEM;
        return NULL;
    }

    /* Clear the tail of the string, setting the trailing NUL. */
    memset(result + (n | 7) - 7, 0, 8);

    if (n) {
        const unsigned char  *s = (const unsigned char *)string;
        unsigned char        *d = (unsigned char *)result;

        while (*s)
            if (*s < 128) {
                *(d++) = *(s++);
            } else
            if (*s < 192) switch (*s) {
                case 164: *(d++) = 226; *(d++) = 130; *(d++) = 172; s++; break;
                case 166: *(d++) = 197; *(d++) = 160; s++; break;
                case 168: *(d++) = 197; *(d++) = 161; s++; break;
                case 180: *(d++) = 197; *(d++) = 189; s++; break;
                case 184: *(d++) = 197; *(d++) = 190; s++; break;
                case 188: *(d++) = 197; *(d++) = 146; s++; break;
                case 189: *(d++) = 197; *(d++) = 147; s++; break;
                case 190: *(d++) = 197; *(d++) = 184; s++; break;
                default:  *(d++) = 194; *(d++) = *(s++); break;
            } else {
                *(d++) = 195;
                *(d++) = *(s++) - 64;
            }
    }

    /* Done. Remember to free() the resulting string when no longer needed. */
    return result;
}

/* Create a dynamically allocated copy of string,
 * changing the encoding from UTF-8 to ISO-8859-15.
 * Unsupported code points are ignored.
*/
char *utf8_to_latin9(const char *const string)
{
    size_t         size = 0;
    size_t         used = 0;
    unsigned char *result = NULL;

    if (string) {
        const unsigned char  *s = (const unsigned char *)string;

        while (*s) {

            if (used >= size) {
                void *const old = result;

                size = (used | 255) + 257;
                result = realloc(result, size);
                if (!result) {
                    if (old)
                        free(old);
                    errno = ENOMEM;
                    return NULL;
                }
            }

            if (*s < 128) {
                result[used++] = *(s++);
                continue;

            } else
            if (s[0] == 226 && s[1] == 130 && s[2] == 172) {
                result[used++] = 164;
                s += 3;
                continue;

            } else
            if (s[0] == 194 && s[1] >= 128 && s[1] <= 191) {
                result[used++] = s[1];
                s += 2;
                continue;

            } else
            if (s[0] == 195 && s[1] >= 128 && s[1] <= 191) {
                result[used++] = s[1] + 64;
                s += 2;
                continue;

            } else
            if (s[0] == 197 && s[1] == 160) {
                result[used++] = 166;
                s += 2;
                continue;

            } else
            if (s[0] == 197 && s[1] == 161) {
                result[used++] = 168;
                s += 2;
                continue;

            } else
            if (s[0] == 197 && s[1] == 189) {
                result[used++] = 180;
                s += 2;
                continue;

            } else
            if (s[0] == 197 && s[1] == 190) {
                result[used++] = 184;
                s += 2;
                continue;

            } else
            if (s[0] == 197 && s[1] == 146) {
                result[used++] = 188;
                s += 2;
                continue;

            } else
            if (s[0] == 197 && s[1] == 147) {
                result[used++] = 189;
                s += 2;
                continue;

            } else
            if (s[0] == 197 && s[1] == 184) {
                result[used++] = 190;
                s += 2;
                continue;

            }

            if (s[0] >= 192 && s[0] < 224 &&
                s[1] >= 128 && s[1] < 192) {
                s += 2;
                continue;
            } else
            if (s[0] >= 224 && s[0] < 240 &&
                s[1] >= 128 && s[1] < 192 &&
                s[2] >= 128 && s[2] < 192) {
                s += 3;
                continue;
            } else
            if (s[0] >= 240 && s[0] < 248 &&
                s[1] >= 128 && s[1] < 192 &&
                s[2] >= 128 && s[2] < 192 &&
                s[3] >= 128 && s[3] < 192) {
                s += 4;
                continue;
            } else
            if (s[0] >= 248 && s[0] < 252 &&
                s[1] >= 128 && s[1] < 192 &&
                s[2] >= 128 && s[2] < 192 &&
                s[3] >= 128 && s[3] < 192 &&
                s[4] >= 128 && s[4] < 192) {
                s += 5;
                continue;
            } else
            if (s[0] >= 252 && s[0] < 254 &&
                s[1] >= 128 && s[1] < 192 &&
                s[2] >= 128 && s[2] < 192 &&
                s[3] >= 128 && s[3] < 192 &&
                s[4] >= 128 && s[4] < 192 &&
                s[5] >= 128 && s[5] < 192) {
                s += 6;
                continue;
            }

            s++;
        }
    }

    {
        void *const old = result;

        size = (used | 7) + 1;

        result = realloc(result, size);
        if (!result) {
            if (old)
                free(old);
            errno = ENOMEM;
            return NULL;
        }

        memset(result + used, 0, size - used);
    }

    return (char *)result;
}

虽然iconv()通常是字符集转换的正确解决方案,但上述两个函数在嵌入式或其他受限环境中肯定很有用。

票数 3
EN

Stack Overflow用户

发布于 2012-06-29 16:18:26

创建从128-255UTF码到latin9 -8字节序列的转换表应该相对容易。你甚至可以使用iconv来做这件事。或者,您可以创建一个包含128-255UTF码的文件,并使用适当的文本编辑器将其转换为latin9 -8。然后,您可以使用此数据来构建转换表。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11258019

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档