欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

用C语言实现GB2312与UTF-8编码间的相互转换操作

最编程 2024-07-26 22:21:19
...

C语言实现GB2312和UTF8之间的编码转换

GB2312

GB2312编码适用于汉字处理、汉字通信等系统之间的信息交换,基本集共收入汉字6763个和非汉字图形字符682个。GB2312中对所收汉字进行了“分区”处理,字符集分成94个区,每区含有94个汉字/符号,这种表示方式也称为区位码。
01-09区为特殊符号。
16-55区为一级汉字,按拼音排序。
56-87区为二级汉字,按部首/笔画排序。
10-15区及88-94区则未有编码。
举例来说,“啊”字是GB2312之中的第一个汉字,它的区位码就是1601。每个汉字及符号以两个字节来表示。第一个字节称为“高位字节”(也称“区字节)”,第二个字节称为“低位字节”(也称“位字节”)。

UTF-8

UTF-8(8位元,Universal Character Set/Unicode Transformation Format)是针对Unicode的一种可变长度字符编码。UTF-8使用1~4字节为每个字符编码:
1)一个US-ASCIl字符只需1字节编码(Unicode范围由U+0000~U+007F)。
2)带有变音符号的拉丁文、希腊文、西里尔字母、亚美尼亚语、希伯来文、阿拉伯文、叙利亚文等字母则需要2字节编码(Unicode范围由U+0080~U+07FF)。
3)其他语言的字符(包括中日韩文字、东南亚文字、中东文字等)包含了大部分常用字,使用3字节编码。
4)其他极少使用的语言字符使用4字节编码。

由此可知,对于中文,GB2312编码占用2个字节,UTF-8编码占用3个字节。

linux下编码工具

  1. 命令行工具
iconv -f encoding -t encoding inputfile

有如下选项可用:

输入/输出格式规范:
-f, --from-code=名称 原始文本编码
-t, --to-code=名称 输出编码

信息:
-l, --list 列举所有已知的字符集

输出控制:
-c 从输出中忽略无效的字符
-o, --output=FILE 输出文件
-s, --silent 关闭警告
--verbose 打印进度信息

示例:下面的命令是将一个utf8编码的文件转换为一个unicode编码的文件

iconv -f utf-8 -t gb2312 utf8file.txt  -o gb2312file.txt
  1. C语言调用iconv库
    下载libiconv库
    根据个人开发板,交叉编译出动态库。
    Ubuntu下好像可以直接包含头文件使用。
#include <iconv.h>

三个主要函数:

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

此函数说明将要进行哪两种编码的转换,tocode是目标编码,fromcode是原编码,该函数返回一个转换句柄,供以下两个函数使用。

size_t iconv(iconv_t cd,char **inbuf,size_t *inbytesleft,char **outbuf,size_t *outbytesleft);

此函数从inbuf中读取字符,转换后输出到outbuf中,inbytesleft用以记录还未转换的字符数,outbytesleft用以记录输出缓冲的剩余空间

注意:inbuf和outbuf都必须是有存储空间的不能定义为常量,如:char *inbuf = “abc” 或者是char *outbuf = "123"这样定义都是错误的。另外inbuf,inbytesleft,outbuf,outbytesleft这几个参数在使用过程中都会改变,最好是先保存一下原值,然后再使用。

int iconv_close(iconv_t cd);

此函数用于关闭转换句柄,释放资源。

代码示例:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "iconv.h"

//iInLen的长度不包括\0,应该用strlen。返回值是处理后的sOut长度
static int Utf8ToGb2312(char *sOut, int iMaxOutLen, const char *sIn, int iInLen)
{
    char *pIn = (char *)sIn;
    char *pOut = sOut;
    size_t ret;
    size_t iLeftLen=iMaxOutLen;
    iconv_t cd;

    cd = iconv_open("gb2312", "utf-8");

    if (cd == (iconv_t) - 1)
    {
        return -1;
    }
	
    size_t iSrcLen=iInLen;
    ret = iconv(cd, &pIn,&iSrcLen, &pOut,&iLeftLen);
	
    if (ret == (size_t) - 1)
    {
        iconv_close(cd);
        return -1;
    }

    iconv_close(cd);

    return (iMaxOutLen - iLeftLen);
}

//iInLen的长度不包括\0,应该用strlen。返回值是处理后的sOut长度
static int Gb2312ToUtf8(char *sOut, int iMaxOutLen, const char *sIn, int iInLen)
{
    char *pIn = (char *)sIn;
    char *pOut = sOut;
    size_t ret;
    size_t iLeftLen=iMaxOutLen;
    iconv_t cd;


    cd = iconv_open("utf-8", "gb2312");
	
    if (cd == (iconv_t) - 1)
    {
        return -1;
    }
    size_t iSrcLen=iInLen;
	
    ret = iconv(cd, &pIn,&iSrcLen, &pOut,&iLeftLen);
    if (ret == (size_t) - 1)
    {
        iconv_close(cd);
        return -1;
    }

    iconv_close(cd);

    return (iMaxOutLen - iLeftLen);
}

int main()
{
	int nRtn = 0;
	char* pszOri = "这是一个中文测试例程";

	printf("byStr[%d]: %s\n", strlen(pszOri), pszOri);
    
    char pszDst[50] = {0};
    
    int iLen = Utf8ToGb2312(pszDst, 50, pszOri, strlen(pszOri)); // Utf8ToGb2312

	printf("iLen: %d    %s\n", iLen, pszDst);

	printf("-----------\n");
    
    char pszGbDst[50] = {0};  
    int iNewLen = Gb2312ToUtf8(pszGbDst, 50, pszDst, iLen); // Gb2312ToUtf8  

	printf("iNewLen: %d    %s\n", iNewLen, pszGbDst);

	return nRtn;
}

以上代码在Linux下编译,记得加上-liconv,代码先将UTF-8转换为GB2312,再从GB2312转为UTF-8,在SecureCRT下,按照GB2312编码方式显示,可以看到iLen后面的中文打印,按照UTF-8编码方式打印,可以看到byStr以及iNewLen后面的中文打印。

参考:Linux下 GB2312和UTF8转换接口

推荐阅读