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