前段时间公司有个启用了手机端访问的系统,但负责测试的姑娘很快发现了 Emoji 的乱码问题。
存储方面,因为那个系统用的 MySQL 所以只要把数据库改成支持 4 字节的 UTF-8 编码就可以正常保存 Emoji 的数据了,但管理人员的数据导出还是一串问号。
托前人的福,很快发现了这个问题的原因在于 POI 库所依赖的 xmlbeans 库上。
喜闻乐见的 tl;dr 环节:
如果你不喜欢这种 dirty hack ,请选择 xmlbeans-2.6.2.jar 。
以下是折腾流水账。
歪果仁的热心解答
Apache 官方提供的 xmlbeans 库,目前最新(实际上也是最后一个)版本是 2.6.0 。
上面说的那个 2.6.2 版本,是好心人修改源码自行编译的。虽然也解决了这个问题,但是我还没有认真去了解这个版本的修改点,所以暂且不表。
基于 stack overflow 上的这个解决方案 我们可以知道,实际上包括 Emoji 的 0x10000 到 0x10FFFF 部分的字符被当成了 bad char 过滤掉了而已。顺便这个判断区间还有遗漏的部分,所以直接改掉判断条件重新打包一个是坠吼滴。
……可我偏偏是个懒人,看到除了下完源码之外还要配置环境和 Ant 我就懒得动了。
最小修改的结论是 4 个字节
还好是 Java ,这要是 C 系列我可能就去搭编译环境了。(我得承认我不会用那些分析工具)
根据说明,问题 Class 分别是 Saver$OptimizedForSpeedSaver.class 和 Saver$TextSaver.class 。我先从 jar 里把这两个文件揪出来。
原本的判断条件里少了 0xD800 到 0xDBFF 的区间,多了 0x10000 到 0x10FFFF 的区间。那我把这个判断数改掉不就好了?
随便找个你喜欢的十六进制编辑器,找一下第一个区间的结束,0xD7FF 。很好,只有一个。
而且接下来几个区间的数值就跟在后面。
这么容易就被我发现了的东西必然…… 是先改了看看效果。
就这么改了 4 字节。然后,把这两个 Class 再塞回原来的位置就行了。
😂😂😂
你非要说 Excel 里显示的 Emoji 跟在网页上看到的不一样那我也没什么好说的了。
同一个 Emoji 就是用 Chrome 和 Edge 分别查看都可能不一样…… 况且 Excel 用的是字体里对应编码的符号,而不是用额外渲染的。
而且字体里没对应的就是显示不出来,组合式的 Emoji 就是显示拆分开的,我能怎么办,我也很绝望啊。
总不能见一个 Emoji 插一个 PNG 吧?