从JavaScript字符串中删除零宽度空格字符

96

我接收用户输入的JS代码,并实时执行以展示输出。

有时代码中会有零宽空格;这真的很奇怪。我不知道用户是如何输入的。例如:"(​$".length === 3

我需要能够从我的JS代码中删除该字符。我该如何做?或者也许有其他方法来执行该JS代码,以使浏览器不考虑这些零宽度空格字符吗?


你是如何推断出存在零宽字符的?仅从长度吗?非BMP字符的长度为2。 - Jukka K. Korpela
当我到字符串的末尾,按下左箭头时,有一点是它不会向左移动,直到再次按下左箭头键。这就是我的推断。 - user1437328
然后您需要分析字符,例如通过编写数字代码来实现。数据可能包含组合标记,因此在向左移动时,两个或多个字符被视为一个单元。 - Jukka K. Korpela
5个回答

166

Unicode有以下零宽字符:

  • U+200B 零宽度空格
  • U+200C 零宽度非连接符Unicode代码点
  • U+200D 零宽度连接符Unicode代码点
  • U+FEFF 零宽度不间断空格Unicode代码点

在JavaScript中从字符串中删除它们,可以使用一个简单的正则表达式:

var userInput = 'a\u200Bb\u200Cc\u200Dd\uFEFFe';
console.log(userInput.length); // 9
var result = userInput.replace(/[\u200B-\u200D\uFEFF]/g, '');
console.log(result.length); // 5

请注意,还有许多可能不可见的符号。例如,ASCII控制字符中的一些。


5
@Iván Castellanos提到了其他一些可能被考虑的字符:U+200E从左到右标记和U+200F从右到左标记。正如我所说,可能还有其他不仅仅是本身可见的符号。 - Mathias Bynens
在DOM加载后,我们如何检测这些值是否实际存在于页面上?谢谢! - klewis
1
var HTMLe=document.getElementsByTagName('html')[0]; HTMLe.outerHTML = HTMLe.outerHTML.replace(/[\u200B-\u200D\uFEFF\u200E\u200F]/g, ''); ...就是这样 - user7892745
如果字符串是Unicode字符的字符串,则此方法无法正常工作 - 仅创建包含它们的变量就会出错。var s = "\ud83d\ude0d\ud83d\ude0d\ud83d\ude0d\ud83d\ude0d\ud83d\ude0d‌​\ud83d\ude0d\ud83d\u‌​de0d\ud83d\ude0d\ud8‌​3d\ude0d\ud83d\ude18‌​\ud83d\ude18\ud83d\u‌​de18" <-- 包含实际的 \u200c 和 d。 - mplungjan
您可以在此链接中查看波斯语的示例:https://regex101.com/r/01tW1A/1 - Milad Xandi

10

我遇到一个问题,一些不可见字符破坏了我的JSON数据,导致出现Unexpected Token ILLEGAL异常,从而导致我的网站崩溃。

这是我的解决方案,使用RegExp变量:

    var re = new RegExp("\u2028|\u2029");
    var result = text.replace(re, '');

关于Javascript和零宽度空格的更多内容,你可以在这里找到: 零宽度空格


或符号在IE中可能会比较慢,因为它是针对多字符匹配进行优化的。但是,在谷歌的V8引擎中,谁知道呢,它可能运行得一样快。 - Jack G
这些不可见的零宽度Unicode字符可以用于隐藏元数据凭据,以供那些敢于通过浏览器复制和粘贴到另一个知道如何接收消息并将零宽度元数据转换回字符缺失的编辑器的用户使用。因此,当您复制和粘贴单词“hi”时,传输的内容是h,然后是一串元数据凭据,最后是i。但源和目标只显示单词“hi”。要防止这些零宽度野蛮人及其波斯信使进入斯巴达护城河将是一场斗争。悲哀! - Eric Leschinski

5
str.replace(/\u200B/g,'');

200B是零宽度空格8203的十六进制表示。将其替换为空字符串即可删除它。


4
[].filter.call( str, function( c ) {
    return c.charCodeAt( 0 ) !== 8203;
} );

过滤每个字符以删除8203字符代码(零宽度空格unicode编号)。

这是一个聪明的解决方案,使用现代JavaScript可以将其简化为一行代码: [].filter.call(strVal, c => c.charCodeAt() !== 8203).join('') - Grant Humphries

2
如果您想在JavaScript中完成此操作,请尝试使用此正则表达式
/([\u200B]+|[\u200C]+|[\u200D]+|[\u200E]+|[\u200F]+|[\uFEFF]+)/g

submit.onclick = evt => {
  const stringToTrim = stringValue.value;
  zeroWidthTrim(stringToTrim);
}

/**
 * Given a string, when it has zero-width spaces in it, then remove them
 *
 * @param {String} stringToTrim The string to be trimmed of unicode spaces
 *
 * @return the trimmed string
 *
 * Regex for zero-width space Unicode characters.
 *
 * U+200B zero-width space.
 * U+200C zero-width non-joiner.
 * U+200D zero-width joiner.
 * U+200E left-to-right mark.
 * U+200F right-to-left mark.
 * U+FEFF zero-width non-breaking space.
 */
function zeroWidthTrim(stringToTrim) {
  const ZERO_WIDTH_SPACES_REGEX = /([\u200B]+|[\u200C]+|[\u200D]+|[\u200E]+|[\u200F]+|[\uFEFF]+)/g;
  console.log('stringToTrim = ' + stringToTrim);
  const trimmedString = stringToTrim.replace(ZERO_WIDTH_SPACES_REGEX, '');
  console.log('trimmedString = ' + trimmedString);
  return trimmedString;
};
<form runat="server">
  <input name="stringValue" id="stringValue" type="text" placeholder="enter your string" value="[&#x200b;&#x200c;]" />
  <input type="button" value="remove zero-width characters" id="submit" />
</form>

运行上述代码片段后,将 stringToTrim 值和 trimmedString 值粘贴到 regex101 测试窗口 中,您会发现 Unicode 字符已从 trimmedString 值中去掉。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接