先來看一段奇怪代碼

上圖的字符串中,只看到了3個字符,打印出的length卻是10。因為這個字符串中隱藏了7個不可見零寬度字符。
什么是零寬度字符
一種不可打印的Unicode字符, 在瀏覽器等環境不可見, 但是真是存在, 獲取字符串長度時也會占位置, 表示某一種控制功能的字符.
常見的零寬字符有哪些
零寬空格(zero-width space, ZWSP)用於可能需要換行處。
Unicode: U+200B HTML: ​
零寬不連字 (zero-width non-joiner,ZWNJ)放在電子文本的兩個字符之間,抑制本來會發生的連字,而是以這兩個字符原本的字形來繪制。
Unicode: U+200C HTML: ‌
零寬連字(zero-width joiner,ZWJ)是一個控制字符,放在某些需要復雜排版語言(如阿拉伯語、印地語)的兩個字符之間,使得這兩個本不會發生連字的字符產生了連字效果。
Unicode: U+200D HTML: ‍
左至右符號(Left-to-right mark,LRM)是一種控制字符,用於計算機的雙向文稿排版中。
Unicode: U+200E HTML: ‎ ‎ 或‎
右至左符號(Right-to-left mark,RLM)是一種控制字符,用於計算機的雙向文稿排版中。
Unicode: U+200F HTML: ‏ ‏ 或‏
字節順序標記(byte-order mark,BOM)常被用來當做標示文件是以UTF-8、UTF-16或UTF-32編碼的標記。
Unicode: U+FEFF
零寬度字符在JavaScript的應用
- 數據防爬
將零寬度字符插入文本中,干擾關鍵字匹配。爬蟲得到的帶有零寬度字符的數據會影響他們的分析,但不會影響用戶的閱讀數據。 - 信息傳遞
將自定義組合的零寬度字符插入文本中,用戶復制后會攜帶不可見信息,達到傳遞作用。
使用零寬度字符加密解密
信息加密解密的思路是, 把字符串轉成二進制0和1, 並用空格把字符隔開, 然后用三種零寬表示0、1、空格, 然后用第四種零寬字符拼起來; 解密反向操作即可.
代碼如下:
// str -> 零寬字符
function strToZeroWidth(str) {
return str
.split('')
.map(char => char.charCodeAt(0).toString(2)) // 1 0 空格
.join(' ')
.split('')
.map(binaryNum => {
if (binaryNum === '1') {
return ''; // ​
} else if (binaryNum === '0') {
return ''; // ‌
} else {
return ''; // ‍
}
})
.join('') // ‎
}
// 零寬字符 -> str
function zeroWidthToStr(zeroWidthStr) {
return zeroWidthStr
.split('') // ‎
.map(char => {
if (char === '') { // ​
return '1';
} else if (char === '') { // ‌
return '0';
} else { // ‍
return ' ';
}
})
.join('')
.split(' ')
.map(binaryNum => String.fromCharCode(parseInt(binaryNum, 2)))
.join('')
}
使用:

過濾零寬度字符
excel表格 中經常出現零寬字符 \u202c \u202d, 上傳后解析或復制到 input 就會有問題,
例如復制 "176xxxx1115"
到控制台獲取 length 是 13 而不是 11, 實際字符串首尾都被 excel 添加了零寬字符 "\u202d176xxxx1115\u202c"
.
所以在 excel表格 中獲取到的數據一般需要先過濾.
str.replace(/[\u200b-\u200f\uFEFF\u202a-\u202e]/g, "");
提取零寬度字符
如果用 零寬字符 加密信息后插入了文本中, 解密時需要先吧 零寬字符 提取出來.
str.replace(/[^\u200b-\u200f\uFEFF\u202a-\u202e]/g, "");