基于内码映射方案的简繁体、全半角、gbk/utf8编码轻量级转换方案,无需三方库

基于内码映射方案的简繁体、全半角、gbk/utf8编码互相转换

一般来说GBK和UTF-8是文字的编码方式,其对应的内码是不一样的,所以GBK和UTF-8的转换需要对内码进行一一映射,然后进行转换。

对于一般系统上的工程,一般使用libiconv即可,但是对于嵌入式或手机操作系统,libiconv显得就有点庞大了。

在这里提供GBK和UTF8转换以及全半角、大小写转换等函数,希望对需要进行轻量开发的同学有所帮助,以后有机会再写写基于libiconv的编码转换。

1. Unicode和UTF8/16/32之间的关系

首先要注意的是unicode是编码字符集,而UTF-8、UTF-16、UTF-32是字符集编码。下面我来具体解释一下:比如汉字的”汉”,在unicode中,汉”的unicode值为0x6C49。问:把这个”汉”字保存到计算机中(硬盘、内存),机器码是多少呢? 学过《计算机组成原理》的人都知道,计算机内部存储的形式都是0101的二进制数字串。”汉”字保存在计算机里肯定也是0101的数字串。”汉”的unicode值是0x6C49,转化为2进制 1101100 01001001,那么把这个”汉”字保存到计算机中也是 1101100 01001001 吗?其实并不是这样的,答案取决于用到的字符集编码是哪种 比如你用到的字符集编码是UTF-8,那么”汉”字在计算机内部保存的值为0xE6B189,也就是111001101011000110001001,可以看到”汉”字变成了3个字节。UTF-8用1-4个字节来保存unicode编码的字符。 而如果用UTF-16来保存,那么”汉”字仍为仍为0x6C49,也就是 1101100 01001001。UTF-16只能是选两字节或四字节来保存字符 而UTF-32就是把所有的字符都用32bit也就是4个字节来表示。 所以这就是编码字符集和字符集编码的区别。

UTF,即Unicode Transformer Format,是Unicode代码点(code point)的实际表示方式,按其基本长度所用位数分为UTF-8/16/32。它也可以认为是一种特殊的外部数据编码,但能够与Unicode代码点做一一对应。也就是其实从本质上说,UTF-8、UTF-16、UTF-32 都是 Unicode 的一种实现,只是实现的方式不同罢了。所以UTF8/16/32是Unicode的衍生,和Unicode是息息相关的。接下来从这三个UTF开始分析和Unicode的关系。

2. 核心方案说明

​ 本方案基于GBK和UTF-8编码,在代码中对内码穷举后,再进行一一映射。包含两个文件 encodenormalize.hencodenormalize.c

使用纯C语言编写,windows、linux下均可用。

// encodenormalize.h

/********************************************************************
* Copyright (C) 2020-20XX   All Rights Reserved.
* All rights reserved.
*
* FileName:encodenormalize.h
* Details :Check GBK character you could do
*     code >= 0x8000 && _pGbk2Utf16[code - 0x8000] != 0
*
* Author  : XX
* version : 1.0.0
* Date    : 2021/11/17 09:08:00
*********************************************************************/

#ifndef __ENCODENORMALIZE_H__
#define __ENCODENORMALIZE_H__

#ifdef __cplusplus
extern "C" {
#endif

#define ENCODE_TO_LOWER        1   // 字母转为小写
#define ENCODE_TO_UPPER        2   // 字母转为大写
#define ENCODE_TO_HALF         4   // 全角符号转为半角符号
#define ENCODE_TO_SIMPLIFIED   8   // 繁体转为简体

    // 初始化
    void encode_normalize_init();
    // 将输入的gbk字符按照 options 的要求进行归一化
    void encode_normalize_gbk(char *text, unsigned options);
    // 将输入的utf8字符按照 options 的要求进行归一化
    void encode_normalize_utf8(char *text, unsigned options);

    // 将gbk编码转为utf-8编码
    int gbk_to_utf8(const char *from, unsigned int from_len, char **to, unsigned int *to_len);
    // 将utf-8编码转为gbk编码
    int utf8_to_gbk(const char *from, unsigned int from_len, char **to, unsigned int *to_len);

#ifdef __cplusplus
}
#endif

#endif // __ENCODENORMALIZE_H__

// encodenormalize.c 因文件太长,不好在这里展示,已上传至CSDN,供有需要的同学免费下载

下载链接: https://download.csdn.net/download/shadow_2011/43517365

3. 使用示例

​ 因为在window下cmd窗口默认为gbk编码,因此单纯的使用cmd调试窗口的输入进行测试,无法正常显示utf8编码的字符,因此本文给出两种示例,一种是使用cmd窗口的简单示例,一种是使用文件作为输入输出的完整测试方案。

3.1 大小写转换,全角转半角,繁体转简体转换

控制台测试方案

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

#include "encodenormalize.h"

int main(int argc, char **argv)
{
    unsigned options = ENCODE_TO_LOWER | ENCODE_TO_HALF | ENCODE_TO_SIMPLIFIED;  // 大写转小写, 全角转半角,繁体转简体
    if (argc > 1) options = atoi(argv[1]);

    encode_normalize_init();

    char *buffer = (char *)malloc(65536);
    memset(buffer, 0, 65536);
    while (fgets(buffer, 65536, stdin))
    {
#ifdef _WIN32
        encode_normalize_gbk(buffer, options);   // 在windows下cmd窗口默认为 gbk
#else
        encode_normalize_utf8(buffer, options);   // 在 linux 下终端窗口默认为 utf-8
#endif // _WIN32
        printf("%s", buffer);
    }
    
    free(buffer);    
    return 0;
}

输出:

normalize_console.png

// 文件输入测试方案

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

#include "encodenormalize.h"
#include "filetool.h"

using namespace filetool;

int main(int argc, char **argv)
{
    // 文件输入使用示例
    unsigned options = ENCODE_TO_LOWER | ENCODE_TO_HALF | ENCODE_TO_SIMPLIFIED;  // 大写转小写, 全角转半角,繁体转简体
    if (argc > 1) options = atoi(argv[1]);

    // 从文件中读取
    const char* sz_file_input_gbk = "../testdata/normalize/gbk_input.txt";
    const char* sz_file_output_gbk = "../testdata/normalize/gbk_output.txt";
    const char* sz_file_input_utf8 = "../testdata/normalize/utf8_input.txt";
    const char* sz_file_output_utf8 = "../testdata/normalize/utf8_output.txt";

    // 从文件中读取待转换的GBK字符
    char *psz_read_gbk = NULL;
    long l_out_buf_size_gbk = 0;
    int n_len_gbk = read_file_by_c(sz_file_input_gbk, &psz_read_gbk, l_out_buf_size_gbk);
    int n_buf_size_gbk = l_out_buf_size_gbk + 1;
    char *psz_input_gbk = new char[n_buf_size_gbk];
    memcpy(psz_input_gbk, psz_read_gbk, n_len_gbk);
    psz_input_gbk[n_len_gbk] = '\0';

    // 从文件中读取待转换的UTF8字符
    char *psz_read_utf8 = NULL;
    long l_out_buf_size_utf8 = 0;
    int n_len_utf8 = read_file_by_c(sz_file_input_utf8, &psz_read_utf8, l_out_buf_size_utf8);
    int n_buf_size_utf8 = l_out_buf_size_utf8 + 1;
    char *psz_input_utf8 = new char[n_buf_size_utf8];
    memcpy(psz_input_utf8, psz_read_utf8, n_len_utf8);
    psz_input_utf8[n_len_utf8] = '\0';

    // 初始化环境
    encode_normalize_init();

    // 测试gbk转换
    encode_normalize_gbk(psz_input_gbk, options);
    int n_size_gbk = strlen(psz_input_gbk);
    int n_write_bytes_gbk = write_file_by_c(sz_file_output_gbk, psz_input_gbk, n_size_gbk);
    printf("encode_normalize_gbk output:%s <==> len=%d\n\n", psz_input_gbk, n_size_gbk);

    // 测试utf8转换
    encode_normalize_utf8(psz_input_utf8, options);
    int n_size_utf8 = strlen(psz_input_utf8);
    int n_write_bytes_utf8 = write_file_by_c(sz_file_output_utf8, psz_input_utf8, n_size_utf8);
    printf("encode_normalize_utf8 output:%s <==> len=%d\n\n", psz_input_utf8, n_size_utf8);

    delete psz_input_gbk;
    delete psz_read_gbk;
    delete psz_input_utf8;
    delete psz_read_utf8;
    
    return 0;
}

输出:
normalize_file.png

3.2 GBK 和 UTF-8 相互转换

// 控制台测试方案

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

#include "encodenormalize.h"

int main(int argc, char **argv)
{
     // 简单使用示例
    encode_normalize_init();
    const char *utf8 = u8"我是utf-8字符!";
    const char *gbk = "我是GBK字符!";
    unsigned int utf8_len = strlen(utf8);
    unsigned int gbk_len = strlen(gbk);
    unsigned int utf8buffer_len = utf8_len * 3 + 1;
    unsigned int gbkbuffer_len = gbk_len * 2 + 1;
    char *utf8buffer = (char *)malloc(utf8buffer_len);
    char *gbkbuffer = (char *)malloc(gbkbuffer_len);
    memset(utf8buffer, 0, utf8buffer_len);
    memset(gbkbuffer, 0, gbkbuffer_len);
    utf8_to_gbk(utf8, utf8_len, &gbkbuffer, &gbkbuffer_len);
    gbk_to_utf8(gbk, gbk_len, &utf8buffer, &utf8buffer_len);
    printf("utf8: %s<=>%d \t gbkbuffer: %s<=>%d\n", utf8, utf8_len, gbkbuffer, gbkbuffer_len);
    printf("gbk: %s<=>%d \t utf8buffer: %s<=>%d\n", gbk, gbk_len, utf8buffer, utf8buffer_len);
    free(utf8buffer);
    free(gbkbuffer);
    
    return 0;
}

输出:
encode_console.png

// 文件输入输出测试方案

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

#include "encodenormalize.h"
#include "filetool.h"

using namespace filetool;

int main(int argc, char **argv)
{
    // 从文件中读取
    const char* sz_file_gbk_input = "../testdata/encoding/gbk_input.txt";
    const char* sz_file_utf_input = "../testdata/encoding/utf8_input.txt";
    const char* sz_file_gbk_output = "../testdata/encoding/utf8_to_gbk_output.txt";
    const char* sz_file_utf_output = "../testdata/encoding/gbk_to_utf8_output.txt";

    // 从文件中读取待转换字符
    char *psz_input_utf8 = NULL;
    char *psz_input_gbk = NULL;
    long l_out_buf_size = 0;
    int n_len_utf8 = read_file_by_c(sz_file_utf_input, &psz_input_utf8, l_out_buf_size);
    int n_len_gbk = read_file_by_c(sz_file_gbk_input, &psz_input_gbk, l_out_buf_size);

    unsigned int utf8buffer_len = n_len_utf8 * 3 + 1;
    unsigned int gbkbuffer_len = n_len_gbk * 2 + 1;
    char *utf8buffer = (char *)malloc(utf8buffer_len);
    char *gbkbuffer = (char *)malloc(gbkbuffer_len);
    memset(utf8buffer, 0, utf8buffer_len);
    memset(gbkbuffer, 0, gbkbuffer_len);

    // 初始化环境
    encode_normalize_init();
    // 执行转换
    utf8_to_gbk(psz_input_utf8, n_len_utf8, &gbkbuffer, &gbkbuffer_len);
    gbk_to_utf8(psz_input_gbk, n_len_gbk, &utf8buffer, &utf8buffer_len);
    printf("psz_input_utf8: %s<=>%d \t gbkbuffer: %s<=>%d\n", psz_input_utf8, n_len_utf8, gbkbuffer, gbkbuffer_len);
    printf("psz_input_gbk: %s<=>%d \t utf8buffer: %s<=>%d\n", psz_input_gbk, n_len_gbk, utf8buffer, utf8buffer_len);

    // 将转换后字符写入文件
    int n_write_bytes_utf8 = write_file_by_c(sz_file_utf_output, utf8buffer, utf8buffer_len);
    int n_write_bytes_gbk = write_file_by_c(sz_file_gbk_output, gbkbuffer, gbkbuffer_len);

    free(utf8buffer);
    free(gbkbuffer);
    delete psz_input_utf8;
    delete psz_input_gbk;

    return 0;
}

输出:

encode_file.png

本文完整测试工程已上传,下载链接:
https://download.csdn.net/download/shadow_2011/43605552

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值