You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在X11库中处理Compound Text编码?

解析X11 COMPOUND_TEXT并转换为UTF-8

COMPOUND_TEXT是X11早期设计的混合字符集编码,通过控制序列切换不同字符集来兼容多语言文本。要将其转换为UTF-8,核心是拆分字符集片段并逐个转码,以下是具体实现思路和代码示例:

核心处理逻辑

  1. 识别控制序列:COMPOUND_TEXT以0x1B(ESC)开头的控制序列切换字符集,格式为ESC % <charset-code>,比如ESC % G对应ISO-8859-1,ESC % @对应GB2312。
  2. 拆分文本片段:按控制序列将整体文本拆分为「字符集标识+对应文本块」的组合。
  3. 片段转码:针对每个文本块,根据字符集标识用转码工具(如libiconv)转换为UTF-8。
  4. 拼接结果:将所有转码后的UTF-8片段拼接成最终字符串。

C语言实现示例(依赖libiconv)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iconv.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>

// 解析COMPOUND_TEXT的字符集标识,返回字符集名称和剩余文本指针
const char* parse_ctext_charset(const unsigned char* ctext, const unsigned char** remaining) {
    *remaining = ctext;
    if (ctext[0] != 0x1B || ctext[1] != '%') {
        return "ISO-8859-1"; // 默认字符集
    }
    switch (ctext[2]) {
        case 'G': return "ISO-8859-1";
        case '@': return "GB2312";
        case 'A': return "JIS_X0208-1983";
        case 'B': return "ISO-2022-JP";
        case 'C': return "ISO-2022-KR";
        default: return "ISO-8859-1";
    }
    *remaining = ctext + 3;
}

// 将COMPOUND_TEXT转换为UTF-8字符串
char* ctext_to_utf8(const unsigned char* ctext, size_t ctext_len) {
    char* utf8_buf = malloc(ctext_len * 4); // 预分配足够的UTF-8空间
    if (!utf8_buf) return NULL;
    char* utf8_ptr = utf8_buf;
    const unsigned char* ptr = ctext;
    const unsigned char* end = ctext + ctext_len;

    while (ptr < end) {
        const char* charset = parse_ctext_charset(ptr, &ptr);
        // 定位当前字符集下的文本片段结尾(下一个控制序列或文本结束)
        const unsigned char* seg_end = ptr;
        while (seg_end < end && seg_end[0] != 0x1B) seg_end++;
        size_t seg_len = seg_end - ptr;

        // 转码当前片段到UTF-8
        iconv_t cd = iconv_open("UTF-8", charset);
        if (cd == (iconv_t)-1) {
            perror("iconv_open failed");
            free(utf8_buf);
            return NULL;
        }
        char* in_buf = (char*)ptr;
        size_t in_left = seg_len;
        char* out_buf = utf8_ptr;
        size_t out_left = (utf8_buf + ctext_len*4) - utf8_ptr;
        
        if (iconv(cd, &in_buf, &in_left, &out_buf, &out_left) == (size_t)-1) {
            // 转码失败时跳过当前片段或替换为占位符
            *out_buf++ = '�';
        }
        utf8_ptr = out_buf;
        iconv_close(cd);
        ptr = seg_end;
    }
    *utf8_ptr = '\0';
    return utf8_buf;
}

// 获取窗口标题,优先处理UTF8_STRING和XA_STRING,最后处理COMPOUND_TEXT
char* get_window_title(Display* dpy, Window win) {
    Atom wm_name = XInternAtom(dpy, "WM_NAME", False);
    Atom utf8_name = XInternAtom(dpy, "UTF8_STRING", False);
    Atom actual_type;
    int format;
    unsigned long nitems, bytes_after;
    unsigned char* prop = NULL;

    // 优先尝试UTF8_STRING
    if (XGetWindowProperty(dpy, win, utf8_name, 0, 1024, False, utf8_name,
                           &actual_type, &format, &nitems, &bytes_after, &prop) == Success && prop) {
        char* title = strdup((char*)prop);
        XFree(prop);
        return title;
    }

    // 处理XA_STRING(ISO-8859-1转UTF-8)
    if (XGetWindowProperty(dpy, win, wm_name, 0, 1024, False, XA_STRING,
                           &actual_type, &format, &nitems, &bytes_after, &prop) == Success && prop) {
        iconv_t cd = iconv_open("UTF-8", "ISO-8859-1");
        char* utf8_buf = malloc(nitems * 4);
        char* in_buf = (char*)prop;
        size_t in_left = nitems;
        char* out_buf = utf8_buf;
        size_t out_left = nitems *4;
        iconv(cd, &in_buf, &in_left, &out_buf, &out_left);
        *out_buf = '\0';
        iconv_close(cd);
        XFree(prop);
        return utf8_buf;
    }

    // 处理COMPOUND_TEXT
    Atom compound_text = XInternAtom(dpy, "COMPOUND_TEXT", False);
    if (XGetWindowProperty(dpy, win, wm_name, 0, 1024, False, compound_text,
                           &actual_type, &format, &nitems, &bytes_after, &prop) == Success && prop) {
        char* utf8_title = ctext_to_utf8(prop, nitems);
        XFree(prop);
        return utf8_title;
    }

    return NULL;
}

注意事项

  • 上述代码只覆盖了常见的字符集控制序列,如需支持更多少见字符集,需参考X11 COMPOUND_TEXT规范补充parse_ctext_charset函数的映射关系。
  • 转码失败时可根据需求选择跳过无效字节或替换为通用占位符�。
  • 实际应用中优先处理UTF8_STRING和XA_STRING,只有当这两种属性获取失败时再处理COMPOUND_TEXT,以降低处理成本。

内容的提问来源于stack exchange,提问作者Ivan Stepanov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 10:25:16