在 Oracle Solaris 中进行应用程序国际化和本地化

退出打印视图

更新时间: 2014 年 7 月
 
 

使用 iconv 函数转换代码集

libc 库中可用于代码转换的 iconv() 函数如下所示:

iconv_open()

代码转换分配函数

iconv()

代码转换函数

iconv_close()

代码转换取消分配函数

iconvctl()

控制和查询代码转换行为

iconvstr()

基于字符串的代码转换函数

iconv 函数可将字符或一系列字符从一种代码集转换为另一种代码集。iconv_open() 函数支持各种代码集。通过运行以下命令可以显示有关系统上当前可用的受支持代码集及其别名的信息:

$ iconv -l

因为 iconv 模块分为多个软件包,您可通过安装额外的软件包来扩展可用转换的缺省列表。缺省安装包括 system/library/iconv/utf-8 软件包,此软件包包含基本的 iconv 模块集,此模块集可在 UTF-8、Unicode 和其他选定代码集之间进行转换。

可使用 Package Manager(软件包管理器)应用程序或 pkg 命令安装额外的软件包。如果使用 Package Manager(软件包管理器)进行安装,在 System/Internationalization 类别中提供了额外的软件包。如果使用 pkg 命令,则使用 system/library/iconv/* 名称模式进行安装。

iconv 转换模块的格式为 fromcode%tocode.so,并且必须存在于 /usr/lib/iconv 目录下的 iconv 模块库中,以便 iconv 函数使用它们。因此,您不可在由 iconv -l 命令列示的任何两个代码集之间进行转换。当安装了所有 iconv 软件包并且所需的模块不可用时,您可使用 Unicode 编码(例如 UTF-32)作为中间代码集执行两步式转换。或者,您也可以开发一个定制转换模块。要创建定制 iconv 转换模块,可使用 geniconvtbl 实用程序。有关 geniconvtbl 实用程序的输入文件格式的信息,请参见 geniconvtbl(4) 手册页。

示例 2-9  使用 iconv_open() 创建转换描述符

以下代码片段说明如何使用 iconv_open() 函数将字符串 złoty(波兰的货币)从单字节 ISO 8859-2 代码集转换到 UTF-8。要使用 iconv 函数执行转换,您需要创建转换描述符并调用 iconv_open() 函数,以及验证此调用是否已成功。

#include <iconv.h>
#include <stdio.h>
iconv_t cd;
 :
cd = iconv_open("UTF-8", "ISO8859-2");
if (cd == (iconv_t)-1) {
   (void) fprintf(stderr, "iconv_open() failed");
    return(1);
}

目标代码集是 iconv_open() 函数的第一个参数。

示例 2-10  使用 iconv() 进行转换

以下代码片段说明如何使用 iconv() 函数将一种代码集转换为另一种代码集。

在进行实际转换之前,需要准备一些变量以保存 iconv 调用返回的信息,例如输出缓冲区、输入和输出缓冲区中留存的字节数等等。

在 ISO 8859-2 代码集中,L WITH STROKE 字符在十六进制中表示为 0xB3。因此,保存输入字符串的输入缓冲区 (inbuf) 设置为 z\xB3oty(用于举例说明)。inbuf 的内容将是读取流或文件的结果。

#include <iconv.h>
#include <stdio.h>
#include <errno.h>

    :
int        ret;
char       *inbuf;
size_t     inbytesleft, outbytesleft;
char       outbuf[BUFSIZ];
char       *outbuf_p;

inbuf = "z\xB3oty";
inbytesleft = 5;      /* the size of the input string */

要使输出缓冲区保存已转换的字符串,至少需要 6 个字节。L WITH STROKE 字符可转换为 Unicode 字符 LATIN SMALL LETTER L WITH STROKE,在 UTF-8 中可表示为双字节序列 0xC5 0x82。

因为在大多数情况下,生成的字符串的实际大小在转换之前是不可知的,因此要确保为输出缓冲区分配足够的额外空间。这种情况下,在 stdio.h 中定义 BUFSIZ 宏就足够了。

outbytesleft = BUFSIZ;   
outbuf_p = outbuf;

此转换调用使用上一示例中的转换描述符 cd

ret = iconv(cd, &inbuf, &inbytesleft, &outbuf_p, &outbytesleft);

调用 iconv 后,需要检查此调用是否已成功。如果调用成功且输出缓冲区内仍有空间,则需要用空字符终止此字符串。

  if (ret != (size_t)-1) {
          if (outbytesleft == 0) {
                  /* Cannot terminate outbuf as a character string; error return */
                  return (-1);
          }
          /* success */
          *outbuf_p = '\0';
            :
  }

如果调用成功,outbuf 中将包含此字符串在 UTF-8 代码集中的十六进制表示形式 \x7a\xc5\x82\x6f\x74\x79z\xc5\x82oty。inbuf 此时将指向已转换字符串的末尾。inbytesleft 将为 0。outbytesleft 将递减 6,此数字是放置到输出缓冲区的字节数。outbuf_p 将指向 outbuf 中输出字符串的末尾。

如果调用失败,则检查 errno 值以处理错误情况,如以下代码片段中所示:

  if (ret != (size_t)-1)) {
          if (errno == EILSEQ) {
                  /* Input conversion stopped due to an input byte that
                   * does not belong to the input codeset.
                   */
                    :
          } else if (errno == E2BIG) {
                  /* Input conversion stopped due to lack of space in
                   * the output buffer.
                   */
                    :
          } else if (errno == EINVAL) {
                  /* Input conversion stopped due to an incomplete
                   * character or shift sequence at the end of the
                   * input buffer.
                   */
                    :
          }
  }

最后,取消分配转换描述符及其关联的所有内存。

iconv_close(cd);