前言
通过实验发现,ESP8266从MQTT读取的数据通常为UTF-8编码,但是项目需求,需要将UTF-8转换为GBK2312进行输出。网上资料过于少或者过于复杂。在这里给大家分享一种稍微方便一点的。
代码如下:
utf2gbk2312.c
#include "utf2gbk2312.h"
UnicodeToGbkMap codeMap[] = {
{0x3001,0xA1A2}, //GB2312:、<br>
{0x3002,0xA1A3}, //GB2312:。<br>
{0x00B7,0xA1A4}, //GB2312:·<br>
{0x02C9,0xA1A5}, //GB2312:ˉ<br>
{0x02C7,0xA1A6}, //GB2312:ˇ<br>
{0x00A8,0xA1A7}, //GB2312:¨<br>
{0x3003,0xA1A8}, //GB2312:〃<br>
{0x2014,0xA1AA}, //GB2312:—<br>
{0xFF5E,0xA1AB}, //GB2312:~<br>
{0x2016,0xA1AC}, //GB2312:‖<br>
{0x2026,0xA1AD}, //GB2312:…<br>
{0x2018,0xA1AE}, //GB2312:‘<br>
{0x2019,0xA1AF}, //GB2312:’<br>
{0x201C,0xA1B0}, //GB2312:“<br>
{0x201D,0xA1B1}, //GB2312:”<br>
{0x3014,0xA1B2}, //GB2312:〔<br>
{0x3015,0xA1B3}, //GB2312:〕<br>
{0x3008,0xA1B4}, //GB2312:〈<br>
{0x3009,0xA1B5}, //GB2312:〉<br>
{0x300A,0xA1B6}, //GB2312:《<br>
{0x300B,0xA1B7}, //GB2312:》<br>
{0x3016,0xA1BC}, //GB2312:〖<br>
{0x3017,0xA1BD}, //GB2312:〗<br>
{0x3010,0xA1BE}, //GB2312:【<br>
{0x3011,0xA1BF}, //GB2312:】<br>
//省略一些
};
#define MAP_SIZE (sizeof(codeMap) / sizeof(UnicodeToGbkMap))
// 从映射表中查找GBK编码
uint16_t unicodeToGbk(uint16_t unicode) {
for (int i = 0; i < MAP_SIZE; i++) {
if (codeMap[i].unicode == unicode) {
return codeMap[i].gbk;
}
}
return 0x3F3F; // "??"表示未知字符
}
// 将UTF-8编码解析为Unicode码点
uint16_t utf8ToUnicode(const char *utf8Str, int *bytesProcessed) {
uint16_t unicode = 0;
uint8_t c = utf8Str[0];
if ((c & 0x80) == 0) { // 单字节UTF-8 (ASCII)
unicode = c;
*bytesProcessed = 1;
} else if ((c & 0xE0) == 0xC0) { // 双字节UTF-8
unicode = ((utf8Str[0] & 0x1F) << 6) | (utf8Str[1] & 0x3F);
*bytesProcessed = 2;
} else if ((c & 0xF0) == 0xE0) { // 三字节UTF-8
unicode = ((utf8Str[0] & 0x0F) << 12) | ((utf8Str[1] & 0x3F) << 6) | (utf8Str[2] & 0x3F);
*bytesProcessed = 3;
}
return unicode;
}
// 将UTF-8字符串转换为GBK2312字符串,保留英文字符
void utf8ToGbk2312(const char *utf8Str, char *gbkStr) {
int i = 0, j = 0;
while (utf8Str[i] != '\0') {
int bytesProcessed = 0;
uint16_t unicode = utf8ToUnicode(&utf8Str[i], &bytesProcessed);
if (unicode >= 0x20 && unicode <= 0x7E) { // 英文字符范围
gbkStr[j++] = utf8Str[i];
} else {
uint16_t gbk = unicodeToGbk(unicode);
if (gbk != 0x3F3F) { // 如果是有效的GBK字符
gbkStr[j++] = (gbk >> 8) & 0xFF;
gbkStr[j++] = gbk & 0xFF;
}
}
i += bytesProcessed;
}
gbkStr[j] = '\0';
}
utf2gbk2312.h
#ifndef UTFTOGBK2312_H
#define UTFTOGBK2312_H
#include "main.h"
// 简化的Unicode到GBK2312的映射表
typedef struct {
uint16_t unicode;
uint16_t gbk;
} UnicodeToGbkMap;
uint16_t unicodeToGbk(uint16_t unicode);
uint16_t utf8ToUnicode(const char *utf8Str, int *bytesProcessed);
void utf8ToGbk2312(const char *utf8Str, char *gbkStr);
#endif
实现原理大致就是通过把UTF-8编码转换为Unicode,再通过映射表,找到对应的GBK2312编码。
编码内容过长,不便展示,请私聊我获取。
注意事项:由于映射表内容过于多,用于单片机的话需要有足够的空间,或者也可以根据使用情况自行裁剪。