如何获得包含零或负宽度字符(如\ u0007或\ b)的输出string的长度

我有一个string'aa\b\u0007\u0007'

 var a = 'aa\b\u0007\u0007'; console.log(a); //=> a //+ 2 beeps console.log(a.length); //=> 5 

这里a.length简单地给我5,但输出的string只是a ,它的长度只有1。

如何得到这个?

这里有几个不同的问题。

首先,不同的环境会以不同的方式呈现string 有些人会将钟形字作为实际的字形; 其他人就像传统的游戏机一样会发出声音。 一些将呈现(一些)零宽度字符作为各种字形。 没有一个“这个string一旦占到退格和零宽度字符多长时间”的解释。

你需要确定你想要在你的情况下应用的规则。 Unicode网站可能会帮助一些传统的解释。 或者如果你只是想解释老式的ASCII码,那将会容易得多,但是我们当然不再生活在一个ASCII的世界里(这是一件好事(tm) )。

一旦你有了规则,取决于它们的复杂程度,你可以用一个或多个正则expression式来应用它们。 例如,这个简单的正则expression式会将退格视为意味着应删除前一个字符,并删除字符代码小于32的所有其他字符(传统上为“控制字符”)。 再次,这是不完整的 ,在该领域外有大量的Unicode零宽度字符(有一个开始有各种零宽度的空间)。 在Unicode范围内做一个彻底的工作将是一个项目,而不是一个微不足道的function。

但只是例如:

 function getInterpretedLength(s) { return s.replace(/(?:.[\b])|[\u0000-\u001f]/g, "").length; } 

第二个问题是对于某些Unicode代码点(松散地,“字符”),JavaScript计算两个 JavaScript字符,而不是一个。 这是因为JavaScriptstring是像UTF-16这样的16位编码 ,只是它们容忍无效的代理对,而一些字符则用两个 16位值编码,而不仅仅是一个。

所以这可能是一个大项目,或者如果你可以根据你实际想要解决的问题来进行充分的限制,那可能会小一些。

看着这个答案 ,你可以试着在获取长度之前使用replace来去除不可打印的字符,如下所示:

 console.log(a.replace(/[^\x20-\x7E]+/g, '').length); 

实际上你可以用canvas来计算字符,但是web中没有像terminal那样的真正的退格字符。 所以,你必须手动计算减去它的backspaces。

 var text = 'aa\b\u0007\u0007'; var context = document.createElement('canvas').getContext("2d"); context.font="30px Courier New"; var length = context.measureText(text).width / context.measureText('x').width - text.match(/\x08/g).length; alert(length); //1