如何找到一个特定的字符串是否有Unicode字符(特别是双字节字符)(How to find whe

2019-07-19 15:58发布

更精确地说,我需要知道是否(如果可能的话,怎么样)我能找到一个给定的字符串是否有双字节字符或没有。 基本上,我需要打开一个弹出窗口显示给定的文本可以包含双字节字符,如中国人或日本人。 在这种情况下,我们需要调整窗口的大小比这将是英语或ASCII。 任何有线索?

Answer 1:

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;
}

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



Answer 2:

我用这一个mikesamuel答案。 不过我注意到也许是因为这种形式的存在应该只有一个前斜线逃生u ,如\u而不是\\u正确地完成这项工作。

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

为我工作:)



Answer 3:

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

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);
}

在这种情况下,如果第一个字符是中国人(这是很可能,如果整个文本是中国人),该函数将被快速并立即返回。 如果不是,它将运行正则表达式,这仍然比逐一检查每个字符更快。



Answer 4:

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

不幸的是,人物在特定的Unicode范围的存在本身是不够的,以确定您需要更多空间。 有许多其中占用大致的空间相同量的具有远高于ASCII范围Unicode代码点其它字符的字符。 印刷报价,用变音符号,某些标点符号,以及各种货币符号的字符以外的低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"))


Answer 5:

下面是基准测试: http://jsben.ch/NKjKd

这是更快:

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

比这个:

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


Answer 6:

为什么不能让窗口调整本身基于运行时的高度/宽度?

在弹出的运行是这样的:

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


文章来源: How to find whether a particular string has unicode characters (esp. Double Byte characters)