33

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

4

6 回答 6

43

我在这个问题上使用了 Mikesamuel 的答案。u但是我注意到也许是因为这种形式,例如,之前应该只有一个转义斜线,\u而不是\\u使它正常工作。

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

为我工作:)

于 2009-11-08T20:06:34.373 回答
32

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

这可能没有您希望的那么快。

于 2008-09-29T13:18:00.100 回答
13

我已经对最佳答案中的两个函数进行了基准测试,并认为我会分享结果。这是我使用的测试代码:

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()立即返回,因此比正则表达式(仍然具有正则表达式的开销)要快得多。

例如对于 string 中国,我得到了这些结果:

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

在这种情况下,如果第一个字符是中文(如果整个文本都是中文的话很可能),该函数将很快并立即返回。如果没有,它将运行正则表达式,这仍然比单独检查每个字符要快。

于 2017-10-12T21:30:51.560 回答
6

实际上,所有字符都是 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"))
于 2008-09-29T08:10:28.887 回答
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;
}
于 2018-11-21T21:29:54.480 回答
0

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

在弹出窗口中运行类似的内容:

window.resizeTo(document.body.clientWidth, document.body.clientHeight);
于 2008-09-29T07:53:59.770 回答