C语言如何将Unicode转义码转换为对应字符并正常打印
C语言Unicode转义序列(\uXXXX)转可显示字符方案
你给出的示例代码存在笔误,定义的string数组未使用,直接用了未定义的buffer,调试时需要先修正这个问题。你当前输出的\u25BA是因为你写的\\u25BA在编译后实际存储的是普通字符\、u、2、5、B、A,不会被C编译器识别为Unicode转义,所以直接输出就是原样内容,对应两种使用场景可以用以下方案解决:
场景1:转义序列是写死在代码的字符串字面量中
如果你用的是C11及以上标准的编译器,直接去掉转义反斜杠即可,编译器会自动把\uXXXX转成对应Unicode字符的UTF-8编码:
#include <stdio.h> #include <string.h> #ifdef _WIN32 #include <windows.h> #endif int main() { #ifdef _WIN32 SetConsoleOutputCP(CP_UTF8); #endif char buffer[32]; memset(buffer, 0, sizeof(buffer)); // 修正转义写法,去掉u前面的多余转义反斜杠 strcpy(buffer, "{\"key\":\"\u25BA\"}"); printf("%s\n", buffer); // 输出 {"key":"►"} return 0; }
注意:Windows环境下需要提前调用SetConsoleOutputCP(CP_UTF8);设置控制台输出编码为UTF-8,否则会显示乱码
场景2:转义序列是运行时动态获取的
如果字符串是从接口、文件等渠道动态读取的自带\u转义,编译器无法提前处理,需要自己实现解析逻辑,解析步骤如下:
- 遍历输入字符串,遇到
\u序列时,读取后续4位十六进制字符转换为整数Unicode码点 - 将Unicode码点编码为1~4字节的UTF-8序列写入输出缓冲区
- 非
\u前缀的普通字符直接写入输出缓冲区
可用的简单实现代码如下:
#include <stdio.h> #include <string.h> #include <stdint.h> #ifdef _WIN32 #include <windows.h> #endif // 把\uXXXX转义的字符串转换为UTF-8编码的字符串 int unicode_unescape(const char *input, char *output, int output_len) { const char *p = input; char *q = output; int remain = output_len; while (*p != '\0' && remain > 0) { if (*p == '\\' && *(p+1) == 'u') { // 读取4位十六进制转码点 uint32_t codepoint = 0; int i; for (i = 0; i < 4; i++) { char c = *(p + 2 + i); codepoint <<= 4; if (c >= '0' && c <= '9') codepoint += c - '0'; else if (c >= 'a' && c <= 'f') codepoint += 10 + c - 'a'; else if (c >= 'A' && c <= 'F') codepoint += 10 + c - 'A'; else break; } if (i != 4) { // 非法\u转义直接拷贝 *q++ = *p++; remain--; continue; } p += 6; // 码点转UTF-8编码 if (codepoint <= 0x7F) { *q++ = codepoint; remain--; } else if (codepoint <= 0x7FF) { if (remain < 2) break; *q++ = 0xC0 | (codepoint >> 6); *q++ = 0x80 | (codepoint & 0x3F); remain -= 2; } else if (codepoint <= 0xFFFF) { if (remain < 3) break; *q++ = 0xE0 | (codepoint >> 12); *q++ = 0x80 | ((codepoint >> 6) & 0x3F); *q++ = 0x80 | (codepoint & 0x3F); remain -= 3; } else if (codepoint <= 0x10FFFF) { if (remain < 4) break; *q++ = 0xF0 | (codepoint >> 18); *q++ = 0x80 | ((codepoint >> 12) & 0x3F); *q++ = 0x80 | ((codepoint >> 6) & 0x3F); *q++ = 0x80 | (codepoint & 0x3F); remain -= 4; } } else { *q++ = *p++; remain--; } } if (remain > 0) *q = '\0'; else output[output_len - 1] = '\0'; return q - output; } int main() { #ifdef _WIN32 SetConsoleOutputCP(CP_UTF8); #endif char buffer[32] = "{\"key\":\"\\u25BA\"}"; char output[32]; unicode_unescape(buffer, output, sizeof(output)); printf("%s\n", output); // 输出 {"key":"►"} return 0; }
如果需要兼容代理对(比如\uD83D\uDE00这类emoji的转义写法),需要额外添加代理对合并的逻辑,上面的实现仅处理单个\uXXXX对应BMP平面码点的场景
内容的提问来源于stack exchange,提问作者dark_vidor
相关产品推荐
相关产品推荐

