关于libiconv:C使用libiconv将iso ISO?8859-1转换为UTF-8

C convert iso ISO?8859-1 to UTF-8 with libconv

我需要将拉丁ISO?8859-1字符编码为UTF-8(以及相反的操作)。

我首先使用了这个答案是否有办法将UTF8转换为iso-8859-1?执行该操作并起作用;

现在,我想使用提供所有转换机制的libiconv,它应该可以帮助我简化代码。

我遵循了此处提供的示例:
https://www.lemoda.net/c/iconv-example/iconv-example.html

我写了一个看起来像这样的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
char *iconvISO2UTF8(char *iso) {
    iconv_t iconvDesc = iconv_open ("ISO?8859-1","UTF-8//TRANSLIT//IGNORE");

    if (iconvDesc == (iconv_t) - 1) {
        /* Something went wrong.  */
        if (errno == EINVAL)
            fprintf(stderr,"conversion from '%s' to '%s' not available","ISO?8859?1","UTF-8");          
        else
            fprintf(stderr,"LibIcon initialization failure");          

        return NULL;
    }

    size_t iconv_value;
    char * utf8;
    size_t len;
    size_t utf8len;
    char * utf8start;

    int len_start;


    len = strlen (iso);
    if (! len) {        
        fprintf(stderr,"iconvISO2UTF8: input String is empty.");          
        return NULL;
    }

    /* Assign enough space to put the UTF-8. */
    utf8len = 2 * len;
    utf8 = calloc (utf8len, sizeof (char));
    if (! utf8) {
        fprintf(stderr,"iconvISO2UTF8: Calloc failed.");          
        return NULL;
    }
    /* Keep track of the variables. */
    utf8start = utf8;
    len_start = len;

    iconv_value = iconv (iconvDesc, & iso, & len, & utf8, & utf8len);
    /* Handle failures. */
    if (iconv_value == (size_t) - 1) {      
        switch (errno) {
                /* See"man 3 iconv" for an explanation. */
            case EILSEQ:
                fprintf(stderr,"iconv failed: Invalid multibyte sequence, in string '%s', length %d, out string '%s', length %d\
"
, iso, (int) len, utf8start, (int) utf8len);            
                break;
            case EINVAL:
                fprintf(stderr,"iconv failed: Incomplete multibyte sequence, in string '%s', length %d, out string '%s', length %d\
"
, iso, (int) len, utf8start, (int) utf8len);              
                break;
            case E2BIG:
                fprintf(stderr,"iconv failed: No more room, in string '%s', length %d, out string '%s', length %d\
"
, iso, (int)  len, utf8start, (int) utf8len);                              
                break;
            default:
                fprintf(stderr,"iconv failed, in string '%s', length %d, out string '%s', length %d\
"
, iso, (int) len, utf8start, (int) utf8len);                            
        }
        return NULL;
    }


    if(iconv_close (iconvDesc) != 0) {
        fprintf(stderr,"libicon close failed: %s", strerror (errno));          
    }

    return utf8start;

}

当我用诸如" abracadabra"之类的普通老式ascii字符来称呼此功能时,iconv可以工作。
但是,一旦我向其中发送突出的字符,例如"éàèü??"然后iconv()调用失败,并显示EILSEQ代码:

iconv failed: Invalid multibyte sequence, in string 'éàèü??', length
6, out string '', length 12

这是一个示例主程序,当存储在以ISO 8859-1编码的源文件中并在以ISO 8859-1作为默认字符集的linux系统上编译时,它会崩溃:

1
2
3
4
5
6
7
8
9
10
11
int main(int argc, char **argv) {
    char *iso1 ="abracadabra";
    char *utf = iconvISO2UTF8(iso1);
    puts(utf);
    free(utf);

    char *iso2 ="éàèü??";
    utf = iconvISO2UTF8(iso2);
    puts(utf);
    free(utf);
}

是否可以使用iconv运行这种转换?
如果是,此代码有什么问题?


请仔细阅读iconv_open(3)手册页:

1
iconv_t iconv_open(const char *tocode, const char *fromcode);

如果您要从ISO 8859-1转换为UTF-8,则可能会出现问题:

1
iconv_t iconvDesc = iconv_open ("ISO?8859-1","UTF-8//TRANSLIT//IGNORE");

应该说

1
iconv_t iconvDesc = iconv_open ("UTF-8//TRANSLIT//IGNORE","ISO?8859-1");