#!/usr/bin/env python3 """gen_big5_table.py — 生成 Big5 双字节 → Unicode BMP 码位表(源码生成物,入仓)。 输出:core/big5_table.h 的 `static const uint16_t big5_2byte[126][190]`。 为什么这样生成(对齐 devdocs/plan/READER_ENGINE_NOTES.md §3.4 的 GB 表做法): - 用 Python 内置 `big5` codec 枚举 2 字节码位(CP950/Big5 全映射)。 - 表大小 = 126 引导字节(0x81..0xFE)× 190 尾字节 = 23,940 项 × 2B = 47,880 B。 - 0 值 = 该 (lead,trail) 不是合法 Big5 双字节(含 trail 0x80..0xA0 区——Big5 尾字节 只取 0x40..0x7E | 0xA1..0xFE);解码器查表得码位,命中 0 → U+FFFD。 - 列布局与 GB 表完全一致(idx(b) = b-0x40-(b>=0x80),跳过 0x7F),故解码器可复用同一 trail 列索引函数。 - 说明(README/编码检测局限):Big5 的双字节区间是 GB18030 双字节区间的**严格子集**, 字节结构无法区分二者;本表用于 Big5 **显式选中时正确解码**,不用于自动检测(见 rdenc.h)。 用法:`python3 tools/gen_big5_table.py > core/big5_table.h` (可用 env BIG5_TABLE_H 覆写输出路径。) """ import sys LEADS = list(range(0x81, 0xFF)) # 0x81..0xFE → 126 个 TRAILS = list(range(0x40, 0x7F)) + list(range(0x80, 0xFF)) # 0x40..0x7E,0x80..0xFE → 190 个 INDEX_OF = {b: i for i, b in enumerate(TRAILS)} # 尾字节 → 列号 def build(): g = [0] * (len(LEADS) * len(TRAILS)) for k, lead in enumerate(LEADS): for j, tr in enumerate(TRAILS): try: s = bytes([lead, tr]).decode('big5') if len(s) == 1 and ord(s) <= 0xFFFF: g[k * len(TRAILS) + j] = ord(s) except UnicodeDecodeError: pass return g def emit(g): rows, cols = len(LEADS), len(TRAILS) out = sys.stdout out.write("/* big5_table.h — Big5 双字节 → Unicode BMP 码位表(生成物,勿手改;\n") out.write(" * 由 tools/gen_big5_table.py 用 python3 `big5` codec 生成)。\n") out.write(" * 布局:big5_2byte[lead-0x81][trail_col];列号 idx(b)= b-0x40-(b>=0x80);\n") out.write(" * 值 0 = 非法 Big5 双字节(如 trail 0x80..0xA0);解码器输出 U+FFFD。*/\n") out.write("#ifndef RD_BIG5_TABLE_H\n#define RD_BIG5_TABLE_H\n\n") out.write("#include \n\n") out.write("#define RD_B5_LEADS %d\n" % rows) out.write("#define RD_B5_TRAILS %d\n" % cols) out.write("#define RD_B5_LEAD0 0x81\n") out.write("#define RD_B5_TRAIL0 0x40\n\n") out.write("/* big5_2byte[126][190]:rdbig5_lookup(lead, trail) 返回 BMP 码位或 0。 */\n") out.write("static const uint16_t big5_2byte[%d][%d] = {\n" % (rows, cols)) for k in range(rows): out.write(" {") for j in range(cols): v = g[k * cols + j] if j % 8 == 0: out.write("\n " if j else "") out.write("0x%04X,%s" % (v, "" if j == cols - 1 else "")) out.write("\n }%s\n" % ("," if k != rows - 1 else "")) out.write("};\n\n#endif /* RD_BIG5_TABLE_H */\n") if __name__ == '__main__': emit(build())