从异8859-15(Latin9)为UTF-8的转换?(Conversion from iso-88

2019-09-18 17:52发布

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

Answer 1:

代码点1127是在这两个拉丁-9(ISO-8859-15)和UTF-8相同。

代码点164使用拉丁9是U + 20AC,\ XE2 \ X82 \ XAC = 226 130 172在UTF-8。
代码点166使用拉丁9是U + 0160,\ XC5 \ XA0 = 197 160在UTF-8。
代码点168使用拉丁9是U + 0161,\ XC5 \ XA1 = 197 161在UTF-8。
代码点180使用拉丁9是U + 017D,\ XC5 \ XBD = 197 189在UTF-8。
代码点184使用拉丁9是U + 017E,\ XC5 \ XBE = 197 190在UTF-8。
代码点188使用拉丁9是U + 0152,\ XC5 \ X92 = 197 146在UTF-8。
代码点189使用拉丁9是U + 0153,\ XC5 \ X93 = 197 147在UTF-8。
代码点190使用拉丁9是U + 0178,\ XC5 \ XB8 = 197 184在UTF-8。

代码点128 .. 191 (除了上面列出的那些)在拉丁语-9都映射到\ XC2 \ X80 .. \ XC2 \ XBF = 194 128 .. 194 191在UTF-8。

代码点192 .. 255在拉丁语-9都映射到\ XC3 \ X80 .. \ XC3 \ XBF = 195 128 .. 195 191在UTF-8。

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

如果第一扫描拉丁-9输入字符串,就可以判断所得到的UTF-8字符串的长度。 如果你想要或需要 - 你的工作在嵌入式系统上,毕竟 - 那么你可以做就地转化,通过对开头,结尾向后工作。

编辑:

以下是您可以使用转换两种方式两种功能。 这些返回你需要一个动态分配的副本free()后使用。 他们只返回NULL时出现(内存,一个错误errno == ENOMEM )。 如果给一个NULL或空字符串要转换,函数返回一个空的动态分配的字符串。

换句话说,你必须拨打free()对这些函数返回的指针,当你与他们进行。 ( free(NULL)是允许的,什么都不做。)

所述latin9_to_utf8()已经被验证,以产生精确的相同的输出iconv如果输入不包含零字节。 该函数使用标准C字符串,即,零字节指示字符串的结尾。

所述utf8_to_latin9()已经被验证,以产生精确的相同的输出iconv如果输入只包含Unicode代码点还在ISO-8859-15,和没有零个字节。 当给定的随机UTF-8字符串,该函数的八个代码点映射拉丁-1至拉丁-9等同物,即货币符号到欧元; 无论的iconv忽略它们还是认为这些错误。

所述utf8_to_latin9()行为意味着该功能是适合Latin 1 - > UTF-8 - > Latin 1 Latin 9 - > UTF-8 - > Latin9往返。

#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()是用于在一般的字符集转换正确的解决方案中,两个以上的功能当然是在嵌入或以其它方式收缩环境是有用的。



Answer 2:

它应该是相对容易地创建从128-255 latin9代码的转换表的字节UTF-8的序列。 你甚至可以使用的iconv做到这一点。 或者你可以创建一个128-255 latin9代码的文件,并使用合适的文本编辑器将其转换为UTF-8。 然后你就可以使用这些数据来建立转换表。



文章来源: Conversion from iso-8859-15 (Latin9) to UTF-8?