2008-09-29 61 views
21

更確切地說,我需要知道是否(以及如果可能的話)如何查找給定字符串是否具有雙字節字符。基本上,我需要打開一個彈出窗口來顯示給定的文本,其中可以包含雙字節字符,如中文或日文。在這種情況下,我們需要調整窗口大小,而不是英語或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

回答

25

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

0

爲什麼不讓窗口根據運行時高度/寬度調整自己的大小?

運行這樣的事情在彈出窗口:

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

像這樣的東西應該在非病理性病例中起作用;當然你需要確保你沒有超過可用的屏幕空間,或者至少要假設合理的限制。 – JasonTrue 2008-09-29 08:12:08

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")) 
23

我對這一個使用mikesamuel的答案。不過,我注意到也許是因爲這種形式,在u之前應該只有一個逃逸斜線, \u而不是\\u,以使其正常工作。

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

爲我工作:)

1

我已經在基準上回答這兩個功能,以爲我會分享成果。下面是測試代碼我使用:

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

在這種情況下,如果第一個字符是中文(如果全文是中文的話很可能),功能會很快並且馬上返回。如果沒有,它將運行正則表達式,這比單獨檢查每個字符還要快。

相關問題