本文通过定位一例线上文案篡位的问题,回顾Unicode中那些看不见的字符。
起
首先和大家一起回忆下 Unicode 的定义:
Unicode 也叫统一码、万国码、单一码,由统一码联盟开发,是计算机科学领域里的一项业界标准,包括字符集、编码方案等。
Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。
比如:
“你好” 对应的Unicode为 “\u4f60\u597d”
“😄😄” 对应的Unicode为 “\ud83d\ude04\ud83d\ude04”
引
讨论 Unicode 的契机是视频号业务有人反馈发表后的文案发生了篡位,具体表现为:
用户发表的内容是: “AAABBBCCC” ,结果发出来之后,文案变成了 “AAABBCBCC”。
这是为什么呢?
分析
首先我尝试使用用户的文案进行发表,发现我发出来的文案顺序是没问题的,这就很奇怪了。
于是我联系用户到了用户,用户将他的文案复制了一份通过微信消息发给了我,粘贴用户发的文案,进行发表,果然复现了问题。
空白占位Unicode字符
首先我怀疑到的是 Unicode 的不可见字符,比如最常见的Unicode 空白占位符:”\uFFFC” ,这个空白占位符是使用最广泛的占位Unicode符号,尤其在 @人 业务里使用最为常见。
@人 有两种类型: @人面板,以及 用户手动输入的 @人,因为这两种@人的方式在用户角度看都是一样的高亮效果,如果想要神不知鬼不觉对这两种不同的@人进行标注,那就可以在@人面板业务下使用”\uFFFC”代替空格。
好,我们继续回来看这个问题,经过查看,发现用户输入的文案中并没有 “\uFFFC” Unicode 不可见字符,那再继续定位。
我们看到用户输入的文案中有 “\u202C” 不可见Unicode字符,看起来它的作用和 “\uFFFC” 是一样的,那能不能在发表的时候将纯文本中的 “\u202C” 使用 空格进行替换呢?
答案是不行! 下面开始进入重点。
成队Unicode字符
“\u202C” Unicode 字符诚然是不可见字符,但它具备团伙效应!
当字符串被 “\u202D” 和 “\u202C” 包裹时,表示字符串是从左到右的强制顺序。
当字符串被 “\u202E” 和 “\u202C” 包裹时,表示字符串会进行翻转。比如:”\u202E好你\u202C“,展示时是会变成: “你好”。
以上两种情况 “\u202c” 起到的都是结束符的作用,意思是到此结束。
当用户的文案是: “\u202E好你\u202C春天”:
- 如果我们不做任何处理,展示出来的文案是:”你好春天”
- 如果我们将”\u202C”不可见Unicode进行过滤,展示出来的文案就是”天春你好”,就错位了!
解决方案
最终的解决方案是只移除专用空白Unicode字符(比如”\uFFFC”),保留团伙Unicode字符(比如”\u202C”),同时为了避免有非法Unicode没有进行过滤,在过滤池中加入动态配置,可以动态的过滤线上非法Unicode (比如iOS可以展示,但安卓无法显示的Unicode字符)。
小结
本文记录了解决过滤文本中不可见Unicode字符的方案,可能你我都会好奇这些奇奇怪怪的不可见Unicode是从哪里产生的?用户如果手动输入怎么会产生这些字符呢?
我收集3例用户的反馈后发现一个共性,他们都是 讯飞输入法 的用户,讯飞输入法 有一个功能允许陈列你过去复制的N条消息,当用户从之前复制的内容中重新粘贴的时候,里面的文本就被塞上了特殊的Unicode字符。
当然至于讯飞输入法为什么会有如此特性,是不可知的,我们要做的就是做好防御编程,以不变应万变。