如何查找某个字符串是否具有unicode字符(特别是双字节字符)

如何查找某个字符串是否具有unicode字符(特别是双字节字符)

问题描述:

更确切地说,我需要知道是否(以及如果可能的话)如何查找给定字符串是否具有双字节字符。基本上,我需要打开一个弹出窗口来显示给定的文本,其中可以包含双字节字符,如中文或日文。在这种情况下,我们需要调整窗口大小,而不是英语或ASCII。 任何人都有线索?如何查找某个字符串是否具有unicode字符(特别是双字节字符)

+0

嗯,我预计这个工作。但它在IE中不起作用。我猜想一些布局问题。无论如何,由于计算要显示的文本长度和高度/宽度的代码已经存在,因此我继续查找代码是否存在双字节字符。这解决了。 – Jay 2008-09-30 05:08:32

+0

使用HTML5,您可以使用Canvas元素的上下文(`var ctx = canvas.getContext('2d')`)来获取宽度文本度量。 `var text_width = ctx.measureText(text).width;`我不确定这个方法如何处理unicode字符,以及所有`measureText`方法当前返回的宽度都是一个耻辱。 – WebWanderer 2015-12-02 21:14:27

JavaScript将内部文本保存为UCS-2,它可以对Unicode的相当广泛的子集进行编码。

但这与您的问题并不紧密。一种解决方案可能是遍历字符串,并在每个位置检查字符代码:

function isDoubleByte(str) { 
    for (var i = 0, n = str.length; i < n; i++) { 
     if (str.charCodeAt(i) > 255) { return true; } 
    } 
    return false; 
} 

这可能不是那么快,你想。

+0

我不知道JavaScript,但是你是不是指UTF-16?没有UCS-16这样的东西;在ISO/IEC 10646标准中存在与Unicode相当的UCS-x编码形式,现在已经过时了。 UCS-2恰好使用了两个字节,因此可以表示前2^16个Unicode字符。相反,UTF-16使用16位单元,但不一定是单个单元。所有Unicode字符都可以表示为UTF-16字节序列。 – 2009-11-08 20:21:21

为什么不让窗口根据运行时高度/宽度调整自己的大小?

运行这样的事情在弹出窗口:

window.resizeTo(document.body.clientWidth, document.body.clientHeight); 
+0

像这样的东西应该在非病理性病例中起作用;当然你需要确保你没有超过可用的屏幕空间,或者至少要假设合理的限制。 – JasonTrue 2008-09-29 08:12:08

其实,所有的字符都是Unicode,从Javascript引擎的角度来看,至少。

不幸的是,仅仅在特定Unicode范围内出现字符将不足以确定您需要更多空间。有许多字符所占的空间大小与Unicode码位远高于ASCII范围的其他字符大致相同。排版引号,带有变音符号的字符,某些标点符号以及各种货币符号不在低ASCII范围内,并且分配在Unicode基本多语言平面上相当不同的位置。

一般来说,我曾经参与过的项目选择为所有语言提供额外空间,或者有时使用javascript来确定具有自动滚动条CSS属性的窗口是否实际上具有会触发滚动条的高度的内容。

如果检测到CJK字符的存在或数量足以确定您需要多余的空间,则可以使用以下范围构造正则表达式: [\ u3300- \ u9fff \ uf900- \ ufaff],并用它来提取匹配的字符数。 (这有些过于粗糙,并且错过了所有非BMP的情况,可能排除了一些其他相关范围,并且很可能包括一些不相关的字符,但这是一个起点)。因为你真正想要的东西就像GDI的MeasureString(或任何其他文本渲染引擎的等价物)一样,你只能够管理一个粗略的启发式方法,而没有沿着全文渲染引擎的方向行事, 。我已经这么做了一段时间,但我认为最接近的HTML/DOM等价物是在div上设置宽度并请求高度(剪切和粘贴重用,如果包含错误,敬请谅解):

o = document.getElementById("test"); 

document.defaultView.getComputedStyle(o,"").getPropertyValue("height")) 

我对这一个使用mikesamuel的答案。不过,我注意到也许是因为这种形式,在u之前应该只有一个逃逸斜线, \u而不是\\u,以使其正常工作。

function containsNonLatinCodepoints(s) { 
    return /[^\u0000-\u00ff]/.test(s); 
} 

为我工作:)

我已经在基准上回答这两个功能,以为我会分享成果。下面是测试代码我使用:

const text1 = `The Chinese Wikipedia was established along with 12 other Wikipedias in May 2001. 中文維基百科的副標題是「海納百川,有容乃大」,這是中国的清朝政治家林则徐(1785年-1850年)於1839年為`; 

const regex = /[^\u0000-\u00ff]/; // Small performance gain from pre-compiling the regex 
function containsNonLatinCodepoints(s) { 
    return regex.test(s); 
} 

function isDoubleByte(str) { 
    for (var i = 0, n = str.length; i < n; i++) { 
     if (str.charCodeAt(i) > 255) { return true; } 
    } 
    return false; 
} 

function benchmark(fn, str) { 
    let startTime = new Date(); 
    for (let i = 0; i < 10000000; i++) { 
     fn(str); 
    } 
    let endTime = new Date(); 

    return endTime.getTime() - startTime.getTime(); 
} 

console.info('isDoubleByte => ' + benchmark(isDoubleByte, text1)); 
console.info('containsNonLatinCodepoints => ' + benchmark(containsNonLatinCodepoints, text1)); 

运行此我:

isDoubleByte => 2421 
containsNonLatinCodepoints => 868 

因此,对于这个特定字符串的正则表达式的解决方案快3倍左右。

但是请注意,对于第一个字符为unicode的字符串,isDoubleByte()立即返回,因此比正则表达式(仍然具有正则表达式的开销)快得多。

例如,对于字符串中国,我得到这些结果:

isDoubleByte => 51 
containsNonLatinCodepoints => 288 

为了得到最好的两个世界,它可能会更好,以两者结合起来:

var regex = /[^\u0000-\u00ff]/; // Small performance gain from pre-compiling the regex 
function containsDoubleByte(str) { 
    if (!str.length) return false; 
    if (str.charCodeAt(0) > 255) return true; 
    return regex.test(str); 
} 

在这种情况下,如果第一个字符是中文(如果全文是中文的话很可能),功能会很快并且马上返回。如果没有,它将运行正则表达式,这比单独检查每个字符还要快。