基于内码映射方案的简繁体、全半角、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.h
和 encodenormalize.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;
}
输出:
// 文件输入测试方案
#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;
}
输出:
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;
}
输出:
// 文件输入输出测试方案
#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;
}
输出:
本文完整测试工程已上传,下载链接:
https://download.csdn.net/download/shadow_2011/43605552