有没有办法将UTF8转换为iso-8859-1?

我的软件在UTF8中得到的字符串比我转换为ISO 8859 1所需的字符串多。我知道UTF8域比iso

8859大。但是UTF8中的数据先前已从ISO上转换,所以我不应该错过任何内容。

我想知道是否存在从UTF8转换为iso-8859-1的简单/直接方法。

谢谢

回答:

这是您可能会发现有用的功能:utf8_to_latin9()。它可以转换为ISO-8859-15(包括欧元,ISO-8859-1但没有),但是对于->

-> 往返的UTF-8-> ISO-8859-1转换部分,它也可以正常工作。ISO-8859-1``UTF-8``ISO-8859-1

该函数将忽略与//IGNOREiconv的标志类似的无效代码点,但不会重组分解的UTF-8序列;也就是说,它不会U+006E

U+0303变成U+00F1。我不麻烦重组,因为iconv也没有。

该函数对于字符串访问非常小心。它永远不会扫描超出缓冲区。输出缓冲区必须比长度长一个字节,因为它总是附加字符串末尾的NUL字节。该函数返回输出中的字符数(字节),不包括字符串末尾的NUL字节。

/* UTF-8 to ISO-8859-1/ISO-8859-15 mapper.

* Return 0..255 for valid ISO-8859-15 code points, 256 otherwise.

*/

static inline unsigned int to_latin9(const unsigned int code)

{

/* Code points 0 to U+00FF are the same in both. */

if (code < 256U)

return code;

switch (code) {

case 0x0152U: return 188U; /* U+0152 = 0xBC: OE ligature */

case 0x0153U: return 189U; /* U+0153 = 0xBD: oe ligature */

case 0x0160U: return 166U; /* U+0160 = 0xA6: S with caron */

case 0x0161U: return 168U; /* U+0161 = 0xA8: s with caron */

case 0x0178U: return 190U; /* U+0178 = 0xBE: Y with diaresis */

case 0x017DU: return 180U; /* U+017D = 0xB4: Z with caron */

case 0x017EU: return 184U; /* U+017E = 0xB8: z with caron */

case 0x20ACU: return 164U; /* U+20AC = 0xA4: Euro */

default: return 256U;

}

}

/* Convert an UTF-8 string to ISO-8859-15.

* All invalid sequences are ignored.

* Note: output == input is allowed,

* but input < output < input + length

* is not.

* Output has to have room for (length+1) chars, including the trailing NUL byte.

*/

size_t utf8_to_latin9(char *const output, const char *const input, const size_t length)

{

unsigned char *out = (unsigned char *)output;

const unsigned char *in = (const unsigned char *)input;

const unsigned char *const end = (const unsigned char *)input + length;

unsigned int c;

while (in < end)

if (*in < 128)

*(out++) = *(in++); /* Valid codepoint */

else

if (*in < 192)

in++; /* 10000000 .. 10111111 are invalid */

else

if (*in < 224) { /* 110xxxxx 10xxxxxx */

if (in + 1 >= end)

break;

if ((in[1] & 192U) == 128U) {

c = to_latin9( (((unsigned int)(in[0] & 0x1FU)) << 6U)

| ((unsigned int)(in[1] & 0x3FU)) );

if (c < 256)

*(out++) = c;

}

in += 2;

} else

if (*in < 240) { /* 1110xxxx 10xxxxxx 10xxxxxx */

if (in + 2 >= end)

break;

if ((in[1] & 192U) == 128U &&

(in[2] & 192U) == 128U) {

c = to_latin9( (((unsigned int)(in[0] & 0x0FU)) << 12U)

| (((unsigned int)(in[1] & 0x3FU)) << 6U)

| ((unsigned int)(in[2] & 0x3FU)) );

if (c < 256)

*(out++) = c;

}

in += 3;

} else

if (*in < 248) { /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */

if (in + 3 >= end)

break;

if ((in[1] & 192U) == 128U &&

(in[2] & 192U) == 128U &&

(in[3] & 192U) == 128U) {

c = to_latin9( (((unsigned int)(in[0] & 0x07U)) << 18U)

| (((unsigned int)(in[1] & 0x3FU)) << 12U)

| (((unsigned int)(in[2] & 0x3FU)) << 6U)

| ((unsigned int)(in[3] & 0x3FU)) );

if (c < 256)

*(out++) = c;

}

in += 4;

} else

if (*in < 252) { /* 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */

if (in + 4 >= end)

break;

if ((in[1] & 192U) == 128U &&

(in[2] & 192U) == 128U &&

(in[3] & 192U) == 128U &&

(in[4] & 192U) == 128U) {

c = to_latin9( (((unsigned int)(in[0] & 0x03U)) << 24U)

| (((unsigned int)(in[1] & 0x3FU)) << 18U)

| (((unsigned int)(in[2] & 0x3FU)) << 12U)

| (((unsigned int)(in[3] & 0x3FU)) << 6U)

| ((unsigned int)(in[4] & 0x3FU)) );

if (c < 256)

*(out++) = c;

}

in += 5;

} else

if (*in < 254) { /* 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */

if (in + 5 >= end)

break;

if ((in[1] & 192U) == 128U &&

(in[2] & 192U) == 128U &&

(in[3] & 192U) == 128U &&

(in[4] & 192U) == 128U &&

(in[5] & 192U) == 128U) {

c = to_latin9( (((unsigned int)(in[0] & 0x01U)) << 30U)

| (((unsigned int)(in[1] & 0x3FU)) << 24U)

| (((unsigned int)(in[2] & 0x3FU)) << 18U)

| (((unsigned int)(in[3] & 0x3FU)) << 12U)

| (((unsigned int)(in[4] & 0x3FU)) << 6U)

| ((unsigned int)(in[5] & 0x3FU)) );

if (c < 256)

*(out++) = c;

}

in += 6;

} else

in++; /* 11111110 and 11111111 are invalid */

/* Terminate the output string. */

*out = '\0';

return (size_t)(out - (unsigned char *)output);

}

请注意,您可以为to_latin9()函数中的特定代码点添加自定义音译,但仅限于一个字符的替换。

就目前而言,该函数可以安全地进行就地转换:输入和输出指针可以相同。输出字符串将永远不会长于输入字符串。如果您的输入字符串有多余的空间(例如,它以NUL终止该字符串),则可以安全地使用上述函数将其从UTF-8转换为ISO-8859-1

/ 15。我特意以此方式编写它,因为它可以在嵌入式环境中为您节省一些精力,尽管这种方法的工作量有限。定制和扩展。

编辑:

在此答案的编辑中,我包括了一对转换函数,用于将拉丁1/9转换为UTF-8(或从UTF-8转换为ISO-8859-1或-15转换为UTF-8)。主要区别在于这些函数返回动态分配的副本,并保持原始字符串不变。

以上是 有没有办法将UTF8转换为iso-8859-1? 的全部内容, 来源链接: utcz.com/qa/416465.html

回到顶部