零宽空格 U+200B 引发的问题及扩展
是这样的,最近在写一个微信公众号的处理脚本,用来替换替换文章中的指定内容。
function getInsertElement(rootElement) { const matchFlag = 'AA' const pList = [...rootElement.querySelectorAll('p')] let matchedElement = pList.find(el => { const text = (el.textContent || el.innerText).replace(/\u00a0/gi, '').trim() return text === matchFlag }) return matchedElement }
上面的方法是脚本的一部分,用于获取文章中指定字符串所在的 DOM 元素,思路是通过 Node.textContent
来匹配的。在调试的时候,发现有时候匹配不上,用「肉眼」看是没问题的,但硬是匹配不上。经过一番排查之后,发现了一个有趣的事情,如图:
在编辑器内有字符 AA
,然后使用 encodeURIComponent($0.textContent)
的编码结果是 AA%E2%80%8B
,所以上面 text === matchFlag
比较结果为 false
,自然就匹配不上了。下面将其转换为 Unicode 字符:
function string2Unicode(str) { return str .split('') .map(value => { const temp = value.charCodeAt(0).toString(16).padStart(4, '0').toUpperCase() if (temp.length > 2) return '\\u' + temp return value }) .join('') } const encodedStr = '%E2%80%8B' const originString = decodeURIComponent(encodedStr) const unicodeStr = string2Unicode(originString) console.log(unicodeStr) // \u200B
转换得出 %E2%80%8B
的 Unicode 编码为 U+200B
,然后查询这里发现它是「零宽空格」,是一种不可见的字符。因此,只要使用正则表达式 /\u200b/gi
,把所有零宽空格干掉就行了。
function getInsertElement(rootElement) { const matchFlag = 'AA' const pList = [...rootElement.querySelectorAll('p')] let matchedElement = pList.find(el => { const text = (el.textContent || el.innerText) .replace(/\u00a0/gi, '') .replace(/\u200b/gi, '') .trim() return text === matchFlag }) return matchedElement }
零宽空格
零宽空格(zero-width space,ZWSP)是一种不可见、不可打印的 Unicode 字符,用于可能需要换行处。
在 Unicode 中,该字元为 U+200B
。在 HTML 中转义字符有:​
、​
、​
。一般情况下,它是不可见的,但一些软件对这些不可见字符做了处理,视觉上可感知。举个例子:
相邻单词之间有一个零宽空格
LoremIpsumDolorSitAmetConsecteturAdipiscingElitSedDoEiusmodTemporIncididuntUtLaboreEtDoloreMagnaAliquaUtEnimAdMinimVeniamQuisNostrudExercitationUllamcoLaborisNisiUtAliquipExEaCommodoConsequatDuisAuteIrureDolorInReprehenderitInVoluptateVelitEsseCillumDoloreEuFugiatNullaPariaturExcepteurSintOccaecatCupidatatNonProidentSuntInCulpaQuiOfficiaDeseruntMollitAnimIdEstLaborum
相邻单词之间无零宽空格
LoremIpsumDolorSitAmetConsecteturAdipiscingElitSedDoEiusmodTemporIncididuntUtLaboreEtDoloreMagnaAliquaUtEnimAdMinimVeniamQuisNostrudExercitationUllamcoLaborisNisiUtAliquipExEaCommodoConsequatDuisAuteIrureDolorInReprehenderitInVoluptateVelitEsseCillumDoloreEuFugiatNullaPariaturExcepteurSintOccaecatCupidatatNonProidentSuntInCulpaQuiOfficiaDeseruntMollitAnimIdEstLaborum
它们在 VS Code 及页面中的展示效果,如图所示:
扩展
除此之外,还有零宽连字、零宽不连字也是不可见字符。
零宽连字(zero-width joiner,ZWJ)是一个控制字符,放在某些需要复杂排版语言(如阿拉伯语、印地语)的两个字符之间,使得这两个本不会发生连字的字符产生了连字效果。其 Unicode 编码为
U+200D
,HTML 转义字符有:‍
、&zwj
。零宽不连字(zero-width non-joiner,ZWNJ)是一个不打印字符,放在电子文本的两个字符之间,抑制本来会发生的连字,而是以这两个字符原本的字形来绘制。其 Unicode 编码为
U+200C
,HTML 转义字符为:‌
。
相信你也看过网友「把幸福的一家几口强行分开」的段子,哈哈:
我们利用前面的 string2Unicode()
方法,将其转化为 Unicode 编码,如下:
其实它们是由多个字符组合而成的,前面所看到的“空字符串”其实就是 U+200D
(零宽连字)。
应用
零宽字符能做什么?
- 传递信息:利用其不可见的特性,在未对零宽字符做过滤的网站插入不可见的隐形文本。
- 水印:同样利用其不可见的特性,给我们的产品添加隐形水印。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论