十六进制转文本
日志、抓包结果和二进制文件里的十六进制串,粘进来就能读出文字,也能把文字转成十六进制。
示例
UTF-8:网页和 Linux 的默认编码,中文占 3 个字节。
结果
估算值是把字节数除以这种编码里一个字符的平均字节数得到的:UTF-8 里一个汉字 3 字节、ASCII 字符 1 字节,所以中文和英文混排时实际字符数会落在这个估算值的两侧。
十六进制转储
00000000 e4 bd a0 e5 a5 bd |...... |
左边是字节偏移量,中间每行 16 个字节,右边是可打印字符的对照,不能打印的字节显示成点。这是 xxd 和 hexdump -C 一直沿用的排法,找文件里的某段内容时比一行长长的十六进制好定位得多。
乱码、BOM 和转储
十六进制本身不带编码信息,它只是字节的写法,同一个字节序列用不同编码解释就是不同的文字。UTF-8 里「你好」是 e4 bd a0 e5 a5 bd,共 6 个字节;GBK 里「你」是 c4 e3、「好」是 ba c3,共 4 个字节。把 GBK 的 c4 e3 交给 UTF-8 解码器,它发现这不是合法的 UTF-8 序列,就会输出替换符,这就是中文乱码最常见的来源。判断办法是看长度:一段中文的 UTF-8 字节数差不多是文字数量的 3 倍,GBK 是 2 倍。
BOM 是文件开头用来表明「我是哪种编码」的几个字节:UTF-8 是 EF BB BF,UTF-16LE 是 FF FE,UTF-16BE 是 FE FF。Windows 记事本保存 UTF-8 时默认带上 BOM,好处是双击打开就能正确识别,坏处是把这个文件喂给程序时,开头的三个字节会被当成正文,脚本报错、JSON 解析失败往往就是它。这里的解码会认得这三种 BOM 并主动去掉,遇到「字节流和所选编码不一致」的情况也会提醒一句。
解析输入时故意做得宽容:空格、换行、逗号、分号、短横线、冒号和 0x、\x 前缀都当作分隔,完全不分隔的连续串也能拆成字节,因为从日志、抓包工具、Wireshark、C 源码和注册表里复制出来的十六进制写法各不相同。宽容的代价是歧义,所以出错时会明确告诉你第几个字符有问题,比如连续的十六进制出现了奇数个数字,就会指着最后那个数字说明它凑不成整字节。
十六进制转储是排查二进制文件的主力工具:左边一列是偏移量,找到可疑内容就能直接跳到文件的对应位置;每行 16 字节是因为 16 是 8 和 4 的公倍数,读起来正好按 8 字节或 4 字节对齐;右侧的 ASCII 对照让夹在二进制里的文本一眼可见,看 PNG、JPEG、PDF 的魔数或者找被截断的字符串都靠它。对应的命令行工具是 Linux 和 macOS 上的 xxd、hexdump -C,Windows 上可以装 HxD。
转回十六进制时的编码选择建议:正常的中文文本一律用 UTF-8;Latin-1 的特点是每个字节都映射到 U+0000 到 U+00FF,任何字节序列都不会丢,所以适合当「字节容器」来搬运原始数据;UTF-16LE 是 Windows 记事本和部分注册表项的习惯写法;GBK 和 Big5 只在对接老系统、老文件时用得上,浏览器没有内置它们的编码器,这里是用解码表反查生成,个别生僻字可能查不到,遇到这种情况换成 UTF-8 处理。