utf8转utf16

参考

在线字符编码转换工具.qr9.net

main.cpp

c 复制代码
/**
 * https://qr9.net/string-encoding
 */

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <windows.h>
/**
 *  UTF-8 到 UTF-16 (无 BOM, 小端) 转换函数
 *
 *  返回值: 实际写入 utf16_buf 的字节数 (不含空终止符)
 *  注意: 不支持 4 字节 UTF-8 序列 (U+10000 以上),遇到时跳过
 */
uint32_t utf8_to_utf16_le(const uint8_t* utf8_str, uint8_t* utf16_buf, uint32_t buf_size) {
    uint32_t utf8_index  = 0;
    uint32_t utf16_index = 0;

    while (utf8_str[utf8_index] != '\0') {
        uint32_t codepoint = 0;
        uint8_t  byte      = utf8_str[utf8_index];

        // 1. 解析 UTF-8 码点
        if ((byte & 0x80) == 0) {
            // 单字节: 0xxxxxxx (U+0000 ~ U+007F)
            codepoint = byte;
            utf8_index += 1;

        } else if ((byte & 0xE0) == 0xC0) {
            // 双字节: 110xxxxx 10xxxxxx (U+0080 ~ U+07FF)
            uint8_t b1 = utf8_str[utf8_index + 1];
            if ((b1 & 0xC0) != 0x80) {
                // 续字节非法(含提前遇到 \0 的情况),跳过首字节
                utf8_index += 1;
                continue;
            }
            codepoint   = ((byte & 0x1F) << 6) | (b1 & 0x3F);
            utf8_index += 2;

        } else if ((byte & 0xF0) == 0xE0) {
            // 三字节: 1110xxxx 10xxxxxx 10xxxxxx (U+0800 ~ U+FFFF, 含常用中文)
            uint8_t b1 = utf8_str[utf8_index + 1];
            uint8_t b2 = utf8_str[utf8_index + 2];
            if ((b1 & 0xC0) != 0x80 || (b2 & 0xC0) != 0x80) {
                utf8_index += 1;
                continue;
            }
            codepoint   = ((byte & 0x0F) << 12) | ((b1 & 0x3F) << 6) | (b2 & 0x3F);
            utf8_index += 3;

        } else {
            // 4 字节序列或非法字节,跳过
            utf8_index += 1;
            continue;
        }

        // 2. 过滤代理码点 (U+D800 ~ U+DFFF),这些码点在 UTF-16 中非法
        if (codepoint >= 0xD800 && codepoint <= 0xDFFF) {
            continue;
        }

        // 3. 输出 UTF-16 LE (此处 codepoint 必定 <= 0xFFFF)
        if (utf16_index + 2 > buf_size) {
            break;
        }
        utf16_buf[utf16_index++] = (uint8_t)(codepoint & 0xFF);         // 低字节
        utf16_buf[utf16_index++] = (uint8_t)((codepoint >> 8) & 0xFF);  // 高字节
    }

    // 4. 写入 UTF-16 空终止符 (占 2 字节)
    if (utf16_index + 2 <= buf_size) {
        utf16_buf[utf16_index]     = 0x00;
        utf16_buf[utf16_index + 1] = 0x00;
    }

    return utf16_index; // 返回写入字节数,不含终止符
}


/**
 *  单个 Unicode 码点 → UTF-16 LE
 *
 *  @param codepoint  Unicode 码点 (U+0000 ~ U+FFFF, 不支持代理对范围)
 *  @param utf16_buf  输出缓冲区,至少 4 字节 (2字节数据 + 2字节终止符)
 *  @param buf_size   缓冲区大小
 *  @return           写入字节数 (不含终止符);码点非法或缓冲区不足返回 0
 */
uint32_t codepoint_to_utf16_le(uint32_t codepoint, uint8_t* utf16_buf, uint32_t buf_size) {
    // 拒绝代理码点和 BMP 以上的码点
    if (codepoint >= 0xD800 && codepoint <= 0xDFFF) return 0;
    if (codepoint > 0xFFFF) return 0;

    if (buf_size < 4) return 0;

    utf16_buf[0] = (uint8_t)(codepoint & 0xFF);
    utf16_buf[1] = (uint8_t)((codepoint >> 8) & 0xFF);
    utf16_buf[2] = 0x00;
    utf16_buf[3] = 0x00;

    return 2;
}

// 辅助函数:以十六进制形式打印内存数据
void print_hex(const char* label, const uint8_t* data, uint32_t len) {
    printf("%s (Len: %d): ", label, len);
    for (uint32_t i = 0; i < len; i++) {
        printf("%02X ", data[i]);
    }
    printf("\n");
}

int main() {
    SetConsoleOutputCP(CP_UTF8);
    uint8_t utf16_buffer[64];

    // --- 测试1: 字符串转换 ---
    const char* test_str = "你好";
    memset(utf16_buffer, 0, sizeof(utf16_buffer));
    print_hex("UTF-8        ", (const uint8_t*)test_str, strlen(test_str));
    uint32_t len = utf8_to_utf16_le((const uint8_t*)test_str, utf16_buffer, sizeof(utf16_buffer));
    print_hex("UTF-16 LE    ", utf16_buffer, len);

    printf("\n");

    // --- 测试2: 单码点转换 ---
    // U+4F60 = '你',  U+0041 = 'A',  U+00E9 = 'é'
    uint32_t codepoints[] = { 0x4F60, 0x0041, 0x00E9 };
    const char* labels[]  = { "U+4F60 ('你')", "U+0041 ('A')", "U+00E9 ('é')" };

    for (int i = 0; i < 3; i++) {
        memset(utf16_buffer, 0, sizeof(utf16_buffer));
        len = codepoint_to_utf16_le(codepoints[i], utf16_buffer, sizeof(utf16_buffer));
        printf("Codepoint %-16s -> ", labels[i]);
        print_hex("UTF-16 LE", utf16_buffer, len);
    }

    return 0;
}

输出

bash 复制代码
C:\Users\PC\CLionProjects\untitled28\cmake-build-debug\untitled28.exe
UTF-8         (Len: 6): E4 BD A0 E5 A5 BD
UTF-16 LE     (Len: 4): 60 4F 7D 59

Codepoint U+4F60 ('你')   -> UTF-16 LE (Len: 2): 60 4F
Codepoint U+0041 ('A')     -> UTF-16 LE (Len: 2): 41 00
Codepoint U+00E9 ('é')    -> UTF-16 LE (Len: 2): E9 00

Process finished with exit code 0
相关推荐
三品吉他手会点灯3 小时前
STM32F103 学习笔记-22-DMA(第1节)-DMA功能框图讲解和DMA初始化结构体讲解
笔记·stm32·单片机·嵌入式硬件·学习
咸甜适中3 小时前
rust语言学习笔记Trait(十一)Deref、DerefMut(解引用)
笔记·学习·rust
AI小技巧4 小时前
商务英语在线学习哪家好?主流平台深度测评与避坑指南
学习
共享家95274 小时前
Langchain的学习(三)
学习·langchain
qq_525513755 小时前
第七章 大模型学习(六) Evaluating the fine-tuned LLM and Conclusion
python·学习·语言模型·大模型
爱喝水的鱼丶6 小时前
SAP-ABAP:变量、常量、结构与内表声明(10篇博客合集) 第九篇:声明阶段的性能优化:如何从定义环节减少程序内存占用与运行耗时
开发语言·学习·算法·性能优化·sap·abap
蓝桉~MLGT6 小时前
Ai-Agent学习历程—— 阶段2——LangChain Core(基本调用、tools、简单上下文等)
学习·大模型·agent
小新同学^O^7 小时前
简单学习 --> GPT架构
学习·架构·transformer