GBK 的编码结构
GBK 在 GB2312 基础上扩充而来,采用变长结构:单字节区 0x00-0x7F 与 ASCII 完全一致,汉字与符号用双字节表示,首字节范围 0x81-0xFE,第二字节范围 0x40-0xFE 且不含 0x7F。它把 GB2312 的 6763 个汉字扩到两万余个,收录了繁体字、生僻字与更多符号,因此在中文字符集里长期扮演「能用就行」的角色。Windows 上标注为 ANSI 的默认中文编码(代码页 936)即由此实现。
基本信息
| 常见标识 | GBK、CP936、MS936;Java 里的 GB2312 有时实际按 GBK 处理 |
|---|---|
| 字节结构 | 单字节 ASCII + 双字节汉字,最长 2 字节 |
| 双字节首字节 | 0x81-0xFE |
| 双字节第二字节 | 0x40-0x7E 与 0x80-0xFE(避开 0x7F) |
| 汉字规模 | GBK 收录 CJK 统一汉字 20902 个(含 GB2312 全部) |
| 与 ASCII 关系 | 单字节区完全兼容,英文内容不受影响 |
典型使用场景
- Windows 中文环境默认读写:记事本以 ANSI 保存、老程序写出的配置文件通常是 CP936
- 旧 Java 工程:file.encoding=GBK 或系统默认编码下的源码、日志文件
- 面向 Excel 的 CSV 导出:不写 BOM 时用 GBK 可被简体中文 Office 直接识别
- 与 legacy 系统对接:老 ERP、票据打印、串口设备出中文时使用 GBK
- 数据迁移前的摸底:统计历史库里哪些表用了 gbk 字符集
判定与转换示例
判定与转换示例
file -i legacy.txt # 输出 charset=iso-8859-1 或 unknown 时,多半是 GBK 系
iconv -f GBK -t UTF-8 legacy.txt -o utf8.txt # 转码;先在小文件上验证
iconv -f GBK -t UTF-8 legacy.txt > /dev/null # 只校验:报 illegal input sequence 说明不是 GBK
python -c "print(open('legacy.txt','rb').read(4))" # 看前几字节是否落在 0x81-0xFE,粗判双字节编码
# Python 侧显式指定编码,避免依赖系统默认值
python -c "print(open('legacy.txt', encoding='gbk').readline())"字节区间对照
| 字节位置 | 取值区间 | 含义 |
|---|---|---|
| 单字节 | 0x00-0x7F | ASCII 字符,与英文编码一致 |
| 双字节首字节 | 0x81-0xFE | 进入双字节状态;0xFF 不是合法取值 |
| 双字节第二字节 | 0x40-0x7E / 0x80-0xFE | 跳过 0x7F,使 DEL 不会出现在字符中间 |
| GB2312 兼容区 | 首字节 0xB0-0xF7 | 常用一级、二级汉字所在区间 |
| 符号与全角区 | 首字节 0xA1-0xA9 | 标点、全角字母数字等 |
解析 GBK 时不能逐字节判定:必须「读首字节 → 判断是否大于 0x7F → 决定后面还有几字节」的状态机。漏掉这一步会把汉字的首字节当成独立字符,产生错位与后续整段乱码。
同一份内容混用 GBK 与 UTF-8 是乱码的主因:GBK 汉字字节在 UTF-8 解码器里属于非法序列(报错或被替换成问号),UTF-8 三字节汉字按 GBK 解则变成两三个不知所云的汉字。定位时先看字节,再谈编码。
跨平台项目应统一到 UTF-8:GBK 无法表示 emoji 与增补平面汉字,且不同系统对 CP936 的实现细节存在历史差异。确需向下兼容时,用 GB18030 作为超集,它是 GBK 的严格扩展,可覆盖 Unicode 全部码位。