记一次IOS通讯录拷贝出的号码含有不可见字符的bug - pod4g/tool GitHub Wiki

一、背景

有一个电话号码输入框

由于从IOS通讯录中拷贝的电话号码138 0000 8888是有空格分割的,所以需要把空格干掉,变成纯净的电话号码13800008888,不然通不过/^\d{11}&/ 的校验

二、去掉空格的方法

function trimAll(str) {
  return str.replace(/\s*/g, '');
}

三、bug现身

后面发现,在IOS11.2中,空格已经被干掉了,但是校验时,还是通不过。说明这个看起来干净的号码中一定含有不可见的字符。。

验证:

'‭13800008888‬'.length === 13

Unicode转码:\u202d13800008888\u202c

可以看到前后个出现了一个非法字符

四、修复

经过查询资料,发现这是Unicode控制字符,Unicode控制字符较多,\u061C\u200E\u200F\u202A\u202B\u202C\u202D\u202E\u2066\u2067\u2068\u2069属于【双向文本控制】字符,拷贝时可能会带有【双向文本控制】字符,故每个都要处理

function trimAll(str) {
  return str.replace(/[\u061C\u200E\u200F\u202A\u202B\u202C\u202D\u202E\u2066\u2067\u2068\u2069\s]*/g, '');
}

五、后续的思考

更好的处理方式

等这个bug修复并上线以后,我才想到一个更好的办法

function trimAll(str) {
  // 干掉所有非数字字符即可,没必要一个个罗列Unicode控制字符,因为语义上来说,手机号码肯定都是数字
  return str.replace(/\D/g, '');

}
  1. 自己解决这个问题用了一天的时间,用时过长,只是直觉上认为号码中有不可见字符,而不是通过'‭13800008888‬'.length === 13 验证一下, 没有聪明劲

六、参考

  1. https://my.oschina.net/u/3242075/blog/1941634
  2. https://zh.wikipedia.org/zh-hans/Unicode控制字符