Node.js RTF解析模块中CJK字符与RTF转义码互转方案咨询
搞定RTF中CJK字符与十六进制转义的互转问题
我之前做过类似的RTF解析工具,你的问题核心其实是没摸透RTF里\'hh转义序列的规则——它不是直接对应UTF-8字节,而是和当前激活的字体(就是你看到的\f1、\f0)绑定的字符集挂钩的。下面给你具体的解决思路和Node.js实现:
先理清楚核心逻辑
RTF里的\'hh表示当前字符集下的一个8位字节,而CJK字符大多是双字节(比如GBK、Big5),所以你看到的\'e2\'8f其实是两个连续的单字节,组合起来才是“鈴”在对应字符集里的完整编码。要完成转换,你需要三步:
- 先搞清楚
\f1对应的字符集是什么(从RTF的字体定义表fonttbl里找) - 把连续的
\'hh字节序列按这个字符集解码成Unicode字符 - 反过来的话,把Unicode字符按目标字符集编码成字节,再转成
\'hh格式
Node.js里的简便实现(用成熟库)
不用自己造轮子,iconv-lite这个轻量库就能搞定几乎所有字符集的转码,比内置功能好用太多。
1. 解码:把\'e2\'8f转成“鈴”
首先你得确认\f1对应的字符集,比如RTF头部的字体表可能长这样:
{\rtf1\ansi\deff0{\fonttbl{\f0\fnil\fcharset0 Arial;}{\f1\fnil\fcharset136 PMingLiU;}}}
这里的\fcharset136就代表\f1用的是Big5字符集(136是Big5的官方字符集代码)。假设是Big5,代码如下:
const iconv = require('iconv-lite'); // 从RTF里提取的字节序列:e2 8f const rtfBytes = Buffer.from(['e2', '8f'], 'hex'); // 按Big5解码成Unicode字符 const cjkChar = iconv.decode(rtfBytes, 'big5'); console.log(cjkChar); // 输出:鈴
如果是GBK的话,把'big5'换成'gbk'就行,其他字符集同理。
2. 编码:把“鈴”转成\'e2\'8f
还是以Big5为例,反向转换的代码:
const iconv = require('iconv-lite'); const targetChar = '鈴'; // 按Big5编码成字节 const charBytes = iconv.encode(targetChar, 'big5'); // 转成RTF要求的\'hh格式 const rtfEscapeStr = charBytes.reduce((result, byte) => { return result + `\\'${byte.toString(16).padStart(2, '0')}`; }, ''); console.log(rtfEscapeStr); // 输出:\'e2\'8f
3. 怎么快速确定字体对应的字符集?
RTF的字体表fonttbl里的\fcharsetN就是关键,N是微软定义的字符集代码,常见的CJK相关代码对应:
- GBK/GB2312:134
- Big5:136
- Shift-JIS(日文):129
- UTF-16:128
你在解析RTF的时候,先把fonttbl里每个\fN对应的\fcharset值存下来,转成对应的字符集名称(比如136 → 'big5'),后续处理转义序列的时候直接用就行。
踩过的坑提醒你
- 别直接把
\'hh当成UTF-8字节!我一开始也犯过这个错,结果转出来全是乱码,因为RTF的转义是跟着当前字体走的 - 如果RTF里没明确写
\fcharset,默认是Windows-1252(ANSI),但CJK字符肯定不会用这个,所以一定要找fonttbl的定义 - 有些RTF会用
\uN来表示Unicode字符(比如\u37329就是“鈴”),这种直接用String.fromCodePoint(37329)就能转,但你遇到的是多字节转义,还是得靠字符集转换
内容的提问来源于stack exchange,提问作者DjH
相关产品推荐
相关产品推荐

