摘要:編碼遲至年月才公布,明確宣布是的超集,即基本平面字符沿用編碼,輔助平面字符定義了個字節的表示方法。的字符函數都受到這一點的影響,無法返回正確結果。但是,這種表示法對字節的碼點無效。以上就可以表示出漢字范圍編碼的正則。
問題出現
在項目中遇到問題
“一二三四五?六七八九十”,被識別為10個字。
一、二、...、十 。呃...似乎有點問題。應該是11個字的啊。
問題就出在?,這個字沒有被識別。
問題分析
看看代碼:
JavaScript允許直接用碼點表示Unicode字符,寫法是"反斜杠+u+碼點"。碼點有十六機制數表示。
但是,這種表示法對4字節的碼點無效。ES6修正了這個問題,只要將碼點放在大括號內,就能正確識別。
根據漢字unicode范圍表發現常用的大多數漢字都可用u4E00-u9FA5來表示。而?的unicode碼是U+20BB7,沒有被包含。所以,我們需要匹配漢字unicode范圍表所有的漢字。
但是, 編碼類似u20BB7的4字節的碼點不能直接被識別。我們需要理解一下js使用的編碼。
JavaScript使用哪一種編碼?
JavaScript用的是UCS-2!
UCS的開發進度快于Unicode,1990年就公布了第一套編碼方法UCS-2,使用2個字節表示已經有碼點的字符。(那個時候只有一個平面,就是基本平面,所以2個字節就夠用了。)UTF-16編碼遲至1996年7月才公布,明確宣布是UCS-2的超集,即基本平面字符沿用UCS-2編碼,輔助平面字符定義了4個字節的表示方法。
由于JavaScript只能處理UCS-2編碼,造成所有字符在這門語言中都是2個字節,如果是4個字節的字符,會當作兩個雙字節的字符處理。JavaScript的字符函數都受到這一點的影響,無法返回正確結果。
unicode
這么多符號,Unicode不是一次性定義的,而是分區定義。每個區可以存放65536個(216)字符,稱為一個平面(plane)。目前,一共有17個(25)平面,也就是說,整個Unicode字符集的大小現在是221。
最前面的65536個字符位,稱為基本平面(縮寫BMP),它的碼點范圍是從0一直到216-1,寫成16進制就是從U+0000到U+FFFF。所有最常見的字符都放在這個平面,這是Unicode最先定義和公布的一個平面。
剩下的字符都放在輔助平面(縮寫SMP),碼點范圍從U+010000一直到U+10FFFF。
UTF-16
到底是把這兩個字節當作一個字符還是與后面的兩個字節一起當作一個字符呢? 這里有一個很巧妙的地方,在基本平面內,從 U+D800 到
U+DFFF 是一個空段,即這些碼點不對應任何字符。因此,這個空段可以用來映射輔助平面的字符。 輔助平面的字符位共有 220220
個,因此表示這些字符至少需要 20 個二進制位。UTF-16將這 20 個二進制位分成兩半,前 10 位映射在 U+D800 到
U+DBFF,稱為高位(H),后 10 位映射在 U+DC00 到
U+DFFF,稱為低位(L)。這意味著,一個輔助平面的字符,被拆成兩個基本平面的字符表示。 因此,當我們遇到兩個字節,發現它的碼點在
U+D800 到 U+DBFF 之間,就可以斷定,緊跟在后面的兩個字節的碼點,應該在 U+DC00 到 U+DFFF
之間,這四個字節必須放在一起解讀。
總的來說,一個輔助平面的字符,被拆成兩個基本平面的字符表示。或者在ES6中可以用"u{20BB7}"來表示。
ES6的支持
ES6可以自動識別4字節的碼點。因此,遍歷字符串就簡單多了。
for (let s of string ) { // ...
}
為了得到字符串的正確長度,可以用下面的方式。
Array.from(string).length [...string].length
碼點表示法,JavaScript允許直接用碼點表示Unicode字符,寫法是"反斜杠+u+碼點"。但是,這種表示法對4字節的碼點無效。ES6修正了這個問題,只要將碼點放在大括號內,就能正確識別。
String.fromCodePoint():從Unicode碼點返回對應字符
String.prototype.codePointAt():從字符返回對應的碼點
String.prototype.at():返回字符串給定位置的字符
正則表達式,ES6提供了u修飾符,對正則表達式添加4字節碼點的支持。
問題解決
所以,我們在正則中表示所有的漢字,需要將不能被直接識別的4字節識別,可以通過ES6的方式,也可以轉換成基本平面來表示。我們需要將所有的漢字區間都包含在匹配公式中,從上面的漢字unicode范圍表看,自己來手寫是很復雜。
還好,有Regenerate可以來完成這件事情。通過它我們可以快速的表示出復雜的正則表達式。
export const character2unicode = regenerate() .addRange(0x4e00, 0x9fa5) .addRange(0x9fa6, 0x9fcb) .addRange(0x3400, 0x4db5) .addRange(0x20000, 0x2a6d6) .addRange(0x2a700, 0x2b734) .addRange(0x2b740, 0x2b81d) .addRange(0x2f00, 0x2fd5) .addRange(0x2e80, 0x2ef3) .addRange(0xf900, 0xfad9) .addRange(0x2f800, 0x2fa1d) .addRange(0xe815, 0xe86f) .addRange(0xe400, 0xe5e8) .addRange(0xe600, 0xe6cf) .addRange(0x31c0, 0x31e3) .addRange(0x2ff0, 0x2ffb) .addRange(0x3105, 0x3120) .addRange(0x31a0, 0x31ba) .toRegExp(); // character2unicode // /[u2E80-u2EF3u2F00-u2FD5u2FF0-u2FFBu3105-u3120u31A0-u31BAu31C0-u31E3u3400-u4DB5u4E00-u9FCBuE400-uE5E8uE600-uE6CFuE815-uE86FuF900-uFAD9]|[uD840-uD868uD86A-uD86C][uDC00-uDFFF]|uD869[uDC00-uDED6uDF00-uDFFF]|uD86D[uDC00-uDF34uDF40-uDFFF]|uD86E[uDC00-uDC1D]|uD87E[uDC00-uDE1D]/
以上就可以表示出漢字unicode范圍編碼的正則。感覺可以很愉快的開工。
參考
https://mathiasbynens.be/note...
http://www.ruanyifeng.com/blo...
https://github.com/mathiasbyn...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/93294.html
摘要:如果轉進制,則位進制只能表示個漢字,這個太少了。假設我們用個進制的字符,則可以表示,表示個漢字綽綽有余,但這時候需要多個字符。 項目地址:https://github.com/xinglie/pi... 壓縮說明 為了便于在網絡上的傳輸,本人想辦法寫了一個壓縮算法,目前這個版本是壓縮好的,帶自解壓功能以下說明壓縮思路: 理想狀態下是使用Stirng.prototype.localCom...
摘要:遍歷漢字,編碼轉漢字網上找了一堆代碼,這個轉那個,那個轉這個,最后發現原生已經有對應的方法了。比如輸出之后的個漢字 js 遍歷漢字,Unicode編碼轉漢字 網上找了一堆代碼,這個轉那個,那個轉這個,最后發現原生js已經有對應的方法了。 MDN 數字轉對應進制的字符串: https://developer.mozilla.org... 寫了個頁面: http://kylebing.c...
摘要:中國大陸幾乎所有的中文系統和國際化的軟件都支持。與相應的國家標準中的其它漢字,以上合計個漢字。,全稱國家標準信息技術中文編碼字符集,是中華人民共和國現時最新的內碼字集,是信息技術信息交換用漢字編碼字符集基本集的擴充的修訂版。 實戰PHP導出Excel-CSV文件 導出后的效果 先給各位看一下導出的效果,而后再進行代碼分析 showImg(https://segmentfault.co...
閱讀 3282·2021-11-18 10:02
閱讀 3447·2021-10-11 10:58
閱讀 3380·2021-09-24 09:47
閱讀 1125·2021-09-22 15:21
閱讀 3944·2021-09-10 11:10
閱讀 3281·2021-09-03 10:28
閱讀 1751·2019-08-30 15:45
閱讀 2144·2019-08-30 14:22