更准确地说,我需要知道我是否(如果可能的话,如何)找到给定的字符串是否有双字节字符。基本上,我需要打开一个弹出窗口来显示可以包含双字节字符的给定文本,例如中文或日文。在这种情况下,我们需要调整窗口大小而不是英语或 ASCII。有人有线索吗?
6 回答
我在这个问题上使用了 Mikesamuel 的答案。u
但是我注意到也许是因为这种形式,例如,之前应该只有一个转义斜线,\u
而不是\\u
使它正常工作。
function containsNonLatinCodepoints(s) {
return /[^\u0000-\u00ff]/.test(s);
}
为我工作:)
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;
}
这可能没有您希望的那么快。
我已经对最佳答案中的两个函数进行了基准测试,并认为我会分享结果。这是我使用的测试代码:
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);
}
在这种情况下,如果第一个字符是中文(如果整个文本都是中文的话很可能),该函数将很快并立即返回。如果没有,它将运行正则表达式,这仍然比单独检查每个字符要快。
实际上,所有字符都是 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"))
这是基准测试: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;
}
为什么不让窗口根据运行时高度/宽度自行调整大小?
在弹出窗口中运行类似的内容:
window.resizeTo(document.body.clientWidth, document.body.clientHeight);