摘要:導(dǎo)語本文源于微信游戲春節(jié)王者搖心愿活動(dòng)英雄語音祝福自定義輸入模塊開發(fā)過程,對(duì)踩過的前端字符編碼的坑進(jìn)行記錄總結(jié)。只規(guī)定了字符編碼,而并沒有規(guī)定具體的編碼方式。
導(dǎo)語
本文源于微信游戲春節(jié)王者搖心愿活動(dòng)英雄語音祝福自定義輸入模塊開發(fā)過程,對(duì)踩過的前端字符編碼的坑進(jìn)行記錄總結(jié)。Unicode 字符
Unicode(中文:萬國碼、國際碼、統(tǒng)一碼、單一碼)是計(jì)算機(jī)科學(xué)領(lǐng)域里的一項(xiàng)業(yè)界標(biāo)準(zhǔn)。它對(duì)世界上大部分的文字系統(tǒng)進(jìn)行了整理、編碼,使得電腦可以用更為簡(jiǎn)單的方式來呈現(xiàn)和處理文字。
簡(jiǎn)單地來說,Unicode 是一種字符編碼,它規(guī)定用一個(gè)碼點(diǎn)表示一個(gè)字符,其范圍為 U+0000~ U+10FFFF , 可以表示超過100萬個(gè)符號(hào)。Unicode 分成17個(gè)平面,其中第1個(gè)平面稱謂基本平面(也稱 BMP),其范圍為 U+0000~ U+FFFF,另外16個(gè)平面稱之為輔助平面,每個(gè)輔助平面擁有65536(即 2^16)個(gè)字符。
Unicode 只規(guī)定了字符編碼,而并沒有規(guī)定具體的編碼方式。因此就產(chǎn)生了不同的編碼方式,包括 UTF-8、UTF-16、UTF-32 等等。
UTF-16本文主要介紹 UTF-16 編碼,不涉及 UTF-8、UTF-32 等其他編碼方式,需要擴(kuò)展閱讀請(qǐng)自行查閱。
UTF-16 是一種變長的編碼方式,可以用2個(gè)字節(jié)或者4個(gè)字節(jié)來編碼 Unicode 字符。UTF-16 使用兩個(gè)字節(jié)編碼 Unicode 字符中的基本平面的字符,使用 4 個(gè)字節(jié)編碼 Unicode 字符中的輔助平面的字符。
UTF-16 使用變長字節(jié)的編碼方式,那么如何判斷一個(gè)字符是基本平面字符還是輔助平面字符?
UTF-16 規(guī)定了BMP中,從 U+D800 到 U+DFFF 之間BMP的區(qū)段是永久保留不映射到字符,可以利用這段區(qū)間來編碼輔助平面的字符。
簡(jiǎn)單來說,從左到右掃描,發(fā)現(xiàn)前兩個(gè)字節(jié)不在 U+D800 到 U+DFFF 之UTF間,則可認(rèn)定這兩個(gè)字節(jié)組成了一個(gè)基本平面的字符,發(fā)現(xiàn)前兩個(gè)字節(jié)處于 U+D800 到 U+DFFF 之間,則需要讀取下兩個(gè)字節(jié),拼湊成四個(gè)字節(jié)組成一個(gè)輔助平面的字符。
前面提到輔助平面有16(即 2^4)個(gè),每個(gè)輔助平面擁有65536(即 2^16)個(gè)字符,因此輔助平面共有 2^20個(gè)字符,也就是說需要 20 位二進(jìn)制位來對(duì)應(yīng)這些字符。
16 * 65536 = 2^4 * 2^16 = 2^20
從 U+D800 到 U+DFFF 之間剛好有 2^11 個(gè)碼元,因此 UTF-16 使用 U+D800 到 U+DBFF 之間(共有2^10個(gè))碼元作為高位, U+DC00 到 U+DFFF 之間(共有 2^10 個(gè))作為低位,這樣子高低位 4 個(gè)字節(jié)組成的編碼方式(代理對(duì))就可以表示一個(gè)輔助平面的字符了。
其中,輔助平面字符 Unicode 到 UTF-16 代理對(duì)的轉(zhuǎn)換規(guī)則如下( c 表示 Unicode 的碼元,H 表示代理對(duì)的高位字節(jié),L 表示代理對(duì)的低位字節(jié)):
H = Math.floor((c - 0x10000) / 0x400) + 0xD800 L = (c - 0x10000) % 0x400 + 0xDC00
以上面的音樂字符為例,其 Unicode 字符的碼元為 U+1F3B6,可以通過 https://codepoints.net/ 查詢到對(duì)應(yīng)字符信息
> H = Math.floor((0x1F3B6 - 0x10000) / 0x400) + 0xD800 0xd83c > L = (0x1F3B6 - 0x10000) % 0x400 + 0xDC00 0xdfb6
通過上面的轉(zhuǎn)換規(guī)則可以算出其代理對(duì)為 ud83cudfb6
UCS-2UCS-2 是 UTF-16 未出世之前的一種編碼方式,可以簡(jiǎn)單理解為 UTF-16的子集。它采用定長2字節(jié)編碼,因此只能表示基本平面的字符,對(duì)于輔助平面字符,它只能理解為這是 “兩個(gè)基本平面字符” ,無法正常表示。
javascript的編碼方式好了,進(jìn)入正題了。前面講了 UTF-16 和 UCS-2,那么 javascript 到底是采用什么編碼的呢?
這個(gè)要分情況來講,javascript 引擎采用 UTF-16 編碼,而 javascript 語言本身的設(shè)計(jì)是采用 UCS-2 編碼方式。
因此,當(dāng)我們使用 UCS-2 編碼方式設(shè)計(jì)的 javascript 接口來處理 UTF-16 編碼的字符,就會(huì)出現(xiàn)很多問題。
比如:
那么如何解決這兩者編碼方式不一致造成的問題呢,有兩種方式:
ES6新版本的ECMA Script提供了新的API來正確處理字符
利用正則表達(dá)式對(duì)其修正(項(xiàng)目也是采用這種方式)
var regexAstralSymbols = /[uD800-uDBFF][uDC00-uDFFF]/g // 獲取字符的長度 function countSymbols(string) { return string // 把代理對(duì)改為一個(gè)BMP的字符. .replace(regexAstralSymbols, "_") // …這時(shí)候取長度就妥妥的啦. .length; } // 獲取前6個(gè)字符 function sliceSymbols(str, limit) { var output = []; var index = 0; var oldStr = str; str = str.replace(regexAstralSymbols, function(input, offset, match) { if( offset > index ) { output = output.concat(match.slice(index, offset).split("")); } index = offset + input.length; output.push(input) return ""; }); if( index < oldStr.length ) { output = output.concat(oldStr.slice(index, oldStr.length).split("")); } return output.slice(0, limit).join(""); }
實(shí)現(xiàn)效果如下:
上面的解決方法基本可以解決大部分的字符問題,但是在遇到某些emoji表情依然會(huì)有些問題。
emojiemoji表情符號(hào)是一種象形文字(圖片符號(hào)),通常以豐富多彩的形式呈現(xiàn)并在文本中以內(nèi)聯(lián)形式使用,起源于日本。Unicode 對(duì) emoji 表情做了劃分范圍,大部分屬于輔助平面字符,目前 Unicode 中收錄的 emoji 表情達(dá)到了 2700多個(gè)。因此,在大部分情況下,使用UTF-16的代理對(duì)來處理emoji 表情是沒有問題。但在 emoji 表情中,還存在著一些字符(Emoji Sequences),它們沒有顯示的樣式,主要起著連接、控制等作用。目前有下面幾種:
控制符 和, 作用是讓基礎(chǔ)Emoji 變成更接近文本樣式( text-style )。
, 作用則是讓基礎(chǔ)Emoji 變成更接近Emoji樣式( emoji-style )。
emoji 除了單個(gè) emoji 符號(hào),還可以通過零寬連接符將多個(gè) emoji 連接成一個(gè) emoji。比如 ud83dudc68是表示一個(gè) man,ud83cudf93表示一個(gè)學(xué)士帽,這兩個(gè)通過零寬連接符連接起來 ud83dudc68u200dud83cudf93就表示一個(gè)男學(xué)生了。
因此,為了解決emoji這些Emoji Sequences,將正則進(jìn)行擴(kuò)展:
var regexAstralSymbols = /[uD800-uDBFF][uDC00-uDFFF][u200D|uFE0F|uFE0E]|[uD800-uDBFF][uDC00-uDFFF]/g;
除了以上兩種比較常見的 Emoji Sequences,其實(shí)還有 Keycap Sequence, Flag Sequence, Tag Sequence, Modifier Sequence等字符,可以參考這里。
參考鏈接https://mathiasbynens.be/note...
https://mathiasbynens.be/note...
https://codepoints.net/
http://www.alloyteam.com/2016...
http://unicode.org/emoji/
https://unicode.org/emoji/cha...
http://unicode.org/emoji/char...
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/92973.html
摘要:具體如下大家都知道,獲取字符串的長度可用來獲取,那么獲取這段字符串的字節(jié)數(shù)呢英文字母肯定和字節(jié)數(shù)都一樣都是而中文字節(jié)數(shù)因此,需要作的就是把中文字符的字節(jié)數(shù)計(jì)算出來。 這篇文章主要介紹了js獲取字符串字節(jié)數(shù)方法,實(shí)例總結(jié)了javascript字符串長度計(jì)算的相關(guān)技巧,需要的朋友可以> 參考下 本文實(shí)例講述js獲取字符串字節(jié)數(shù)的方法。分享給大家供大家參考。具體如下: 大家都知道,獲取字符串...
摘要:最近在看書的時(shí)候突然糾結(jié)于相關(guān)字符編碼,查了一些資料,并寫了這篇文章,順帶做下筆記,希望能幫到一些人。解決傳統(tǒng)的字符編碼方案的局限。 最近在看書的時(shí)候突然糾結(jié)于Unicode相關(guān)字符編碼,查了一些資料,并寫了這篇文章,順帶做下筆記,希望能幫到一些人。文章如果有寫的不妥的或者不正確的地方還請(qǐng)大家糾正。 Unicode 編碼 Unicode是一個(gè)符號(hào)集,它對(duì)世界上大部分的文字系統(tǒng)進(jìn)行了整理...
原始數(shù)據(jù)類型(9種) 基本數(shù)據(jù)類型: 整形(integer)、浮點(diǎn)型(float)、字符串(string)、布爾型(boolean) 復(fù)合數(shù)據(jù)類型:數(shù)組(array)、對(duì)象(object)、callable(可調(diào)用) 特殊數(shù)據(jù)類型:資源類型(resource) 和 NULL 變量相關(guān)處理函數(shù) is_bool($var)????????判斷是否為布爾型 is_int($var)????...
摘要:實(shí)現(xiàn)了搜索這一功能,接下來就是要把這一部分嵌入到一個(gè)平臺(tái),因此我開始接觸編程以及前端。之前我對(duì)前端幾乎沒有什么了解,因此這一周除了體檢被檢查出來早搏參加入學(xué)典禮之外,就是在琢磨,,了,并結(jié)合需求開發(fā)了網(wǎng)站的一部分。 今年暑假大部分時(shí)間是在要學(xué)校,前一階段一直在學(xué)習(xí)Scala和理解Spark,但是苦于沒有實(shí)際上手的項(xiàng)目,盡管看了不少論文和書,但不敢說自己理解的有多深刻,所以我打算暫時(shí)擱置...
摘要:是一個(gè)系統(tǒng)支持的所有字符的集合,包括各國家文字標(biāo)點(diǎn)符號(hào)圖形符號(hào)數(shù)字等字符集簡(jiǎn)體中文碼表。支持中國國內(nèi)少數(shù)民族的文字,同時(shí)支持繁體漢字以及日韓漢字等字符集為表達(dá)任意語言的任意字符而設(shè)計(jì),是業(yè)界的一種標(biāo)準(zhǔn),也稱為統(tǒng)一碼標(biāo)準(zhǔn)萬國碼。 1 File1.1 File類的概述和構(gòu)造方法File: 它是文件和目錄路徑名的抽象...
閱讀 2028·2021-10-09 09:41
閱讀 1603·2021-09-28 09:36
閱讀 1105·2021-09-26 09:55
閱讀 1295·2021-09-10 11:17
閱讀 1150·2021-09-02 09:56
閱讀 2764·2019-08-30 12:58
閱讀 2937·2019-08-29 13:03
閱讀 1857·2019-08-26 13:40