一个看起来只有2个字长度却有8的字符串引起的bug
前言
我们有一个需求,用户的昵称如果长度超过6就截取前6个字符并显示…。今天,测试突然提了一个bug,某个用户的昵称只显示了…,鼠标hover的时候又显示2个字的昵称。刚看到这个问题的时候我也是一头雾水。
找出原因
在看到这个现象后,我发现其他昵称都显示正常,但实在摸不着头脑这到底是怎么回事。然后查看了一下其他2个字的昵称是没问题的,然后通过console.log
发现这个昵称居然长度有8,走了截取的分支。然后通过google发现这里面应该包含了零宽字符。
其实,第一时间就应该想到这个字符串不对劲的,但完全忘记了零宽字符
的存在,走了不少弯路。
在查找的过程中发现,Array.from
可以查看字符串的真实长度,除了emoji
。
不过Array.from
并不能解决我的问题。
使用正则匹配unicode码点过滤零宽字符
在网上找了个方法来过滤掉这些看不见的字符,最常见的解决方案就是下面这行代码。
1 | str.replace(/[\u200b-\u200f\uFEFF\u202a-\u202e]/g, ""); |
然而并没有用,我开始怀疑是不是这个方法有问题,然后遍历了这个昵称,把它的每个字符都转换成码点,发现这个昵称里的零宽字符并不是常见的这几种。
后来,又找到了一个比较完善的码点正则,但它太完善了,很长很长,也会过滤掉emoji
,这可不行,用户昵称可能会包含emoji
的。(这里就不贴出来代码了,太长了而且不适合我的情况。)
使用正则匹配unicode类别
一个字符有多种unicode属性,而正则支持按unicode属性匹配。
1 | function stripNonPrintableAndNormalize(text, stripSurrogatesAndFormats) { |
总结
这个昵称其实就是包含了&nobreak;
,通过unicode类别匹配可以过滤掉它。
我之前有在原贴用户主页的控制台中看见了&nobreak;
,但当时居然没当回事,以为是别人对昵称做的处理。如果直接搜它马上就能解决问题了,有不少人遇到non-break-space
引发的bug。谨以此记,吸取教训。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 河豚的前端之路!
评论