摘要:編碼轉換為編碼下面讓我們來看下如何將編碼的數(shù)據(jù)轉換為編碼的數(shù)據(jù)。該方法是將碼進行編碼轉換,從而得到編碼的數(shù)據(jù)。
概述
當你在前端需要通過二進制數(shù)據(jù)與服務端進行通信時,你可能會遇到二進制數(shù)據(jù)的編碼問題。大部分服務端的字符串編碼類型都為UTF-8,而JavaScript中字符串編碼類型是UTF-16,因此,你需要一個能夠將字符串在兩種編碼方式間進行轉換的方法。
本文通過對utfx.js這個庫的代碼進行分析,帶大家深入了解UTF8和UTF16這兩種編碼方式在JavaScript中的轉換方法,同時加深對Unicode中UTF-8和UTF-16兩種編碼方式的具體原理的理解。
本文的主要內(nèi)容為:
utfx.js API簡單介紹
UTF-16編碼轉換為UTF-8編碼
UTF-8編碼字符串長度計算
實驗性功能:window.TextEncoder
如果有讀者不了解Unicode中UTF-8和UTF-16兩種編碼方式的具體原理,可以閱讀我的前一篇博客——Unicode中UTF-8與UTF-16編碼詳解。
如果有讀者想要了解該庫相關的轉換使用場景,可以閱讀我之前的博客WebSocket系列之JavaScript字符串如何與二進制數(shù)據(jù)間進行互相轉換。
utfx.js API簡介在進行具體的代碼詳解之前,我們先來了解下我們需要介紹的庫——utfx.js。我們只有了解了這個庫的使用方法,我們才能夠更好的理解源碼。
utfx.js代碼不多,一共只有八個API接口,分別為:
encodeUTF8:將UTF-8編碼的字符串code碼轉換為二進制bytes。
decodeUTF8:將UTF-8編碼的二進制bytes解碼城字符串code碼。
UTF16toUTF8:將UTF-16的字符轉換為UTF-8的code碼。
UTF8toUTF16:將UTF-8的code碼轉換為UTF-16的字符。
encodeUTF16toUTF8:將UTF-16編碼的字符轉換為UTF-8編碼的bytes。
decodeUTF8toUTF16:將UTF-8編碼的bytes轉換為UTF-16編碼的字符。
calculateCodePoint:計算UTF-8編碼下的字符長度。
calculateUTF8:計算需要用來存儲UTF-8編碼code碼的bytes的長度。
calculateUTF16asUTF8:計算UTF-16編碼的字符在轉換成UTF-8后需要的存儲長度。
下面,我們將挑選幾個具有代表性的API,針對其實現(xiàn)的具體代碼來進行分析,幫助大家快速理解這兩種編碼方式。
UTF-16編碼轉換為UTF-8編碼下面讓我們來看下如何將UTF-16編碼的數(shù)據(jù)轉換為UTF-8編碼的數(shù)據(jù)。
當我們需要把UTF-16的數(shù)據(jù)轉換為UTF-8編碼的數(shù)據(jù)時,最好的方法肯定是將UTF-16編碼的數(shù)據(jù)轉換為通用的Unicode碼,在進行UTF-8編碼。我們通過UTF16toUTF8和encodeUTF8方法的代碼來進行具體解析。
UTF16toUTF8這個函數(shù)名看上去是直接將UTF-16編碼的bytes數(shù)據(jù)轉換為UTF-8編碼的的Bytes數(shù)據(jù)。其實是,將UTF-16編碼的bytes數(shù)據(jù)轉換為Unicode對應的二進制數(shù)據(jù)。
/** * UTF16數(shù)據(jù)轉換到Unicode數(shù)據(jù) * @param src 數(shù)據(jù)源,類型為Function,調(diào)用一次返回1 Byte數(shù)據(jù),如果到達字符串末尾則返回null * @param dst 處理函數(shù),類型為Function,得到的Bytes作為參數(shù)傳遞給dst函數(shù) */ utfx.UTF16toUTF8 = function (src, dst) { var c1, c2 = null; while (true) { // 到達結尾調(diào)用src函數(shù)得到null后會進入此分支邏輯 if ((c1 = c2 !== null ? c2 : src()) === null) break; //Unicode標準規(guī)定,U+D800~U+DFFF的值不對應任何字符,即專門用來判斷是否為高位代理 if (c1 >= 0xD800 && c1 <= 0xDFFF) { if ((c2 = src()) !== null) { // 如果Unicode碼范圍超過U+FFFF則會進入此分支邏輯(兩段:第一段大于U+D800,第二段大于U+DC00) if (c2 >= 0xDC00 && c2 <= 0xDFFF) { // 第一步:用c1還原高10位;第二步:用c2還原低十位;第三步:加上減去的0x10000 dst((c1 - 0xD800) * 0x400 + c2 - 0xDC00 + 0x10000); c2 = null; continue; } } } dst(c1); } if (c2 !== null) dst(c2); };
根據(jù)代碼和上面的注釋,大家應該就能看懂對應代碼,因此在此不做過多贅述。我們接著看將Unicode碼轉換為UTF-8編碼的方法。
encodeUTF8該方法是將Unicode碼進行UTF-8編碼轉換,從而得到UTF-8編碼的Bytes數(shù)據(jù)。
/** * Unicode數(shù)據(jù)轉換為UTF-8數(shù)據(jù) * @param src 數(shù)據(jù)源,類型為Function,調(diào)用一次返回1 Byte數(shù)據(jù),如果到達字符串末尾則返回null * @param dst 處理函數(shù),類型為Function,得到的Bytes作為參數(shù)傳遞給dst函數(shù) */ utfx.encodeUTF8 = function (src, dst) { var cp = null; if (typeof src === "number") cp = src, src = function () {return null;}; while (cp !== null || (cp = src()) !== null) { if (cp < 0x80) // 1 byte存儲情況 dst(cp & 0x7F); else if (cp < 0x800) // 2 byte存儲情況 dst(((cp >> 6) & 0x1F) | 0xC0), dst((cp & 0x3F) | 0x80); else if (cp < 0x10000) // 3 byte存儲情況 dst(((cp >> 12) & 0x0F) | 0xE0), dst(((cp >> 6) & 0x3F) | 0x80), dst((cp & 0x3F) | 0x80); else // 4 byte存儲情況 dst(((cp >> 18) & 0x07) | 0xF0), dst(((cp >> 12) & 0x3F) | 0x80), dst(((cp >> 6) & 0x3F) | 0x80), dst((cp & 0x3F) | 0x80); cp = null; } };
上面的代碼與UTF-8編碼規(guī)范中的方式基本一致,如果沒有理解相關規(guī)范,可以先閱讀本文概述中提到的前一篇博客。
編碼字符串長度計算當我們給出一串Unicode碼時,我們需要知道申請多大的ArrayBuffer來進行轉換后的數(shù)據(jù)存儲。正好,這個庫還提供了根據(jù)Unicode碼的長度或者UTF-16編碼格式的數(shù)據(jù)來計算UTF-8數(shù)據(jù)的存儲長度。
下面我們來介紹calculateUTF8和calculateUTF16asUTF8這兩個方法。
calculateUTF8該方法是通過Unicode碼來計算轉換為UTF-8編碼后所占存儲長度。
/** * 根據(jù)Unicode編碼來計算轉換成UTF-8編碼后需要的存儲長度 * @param src 數(shù)據(jù)源,類型為Function,調(diào)用一次返回1 Byte數(shù)據(jù),如果到達字符串末尾則返回null */ utfx.calculateUTF8 = function (src) { var cp, l = 0; while ((cp = src()) !== null) // 占1 Byte的范圍是0~0x7F;占2 Byte的范圍是0x80~0x7FF;占三個字節(jié)的范圍是0x800~0xFFFF;占4個字節(jié)的范圍為:0x10000~0x10FFFF l += (cp < 0x80) ? 1 : (cp < 0x800) ? 2 : (cp < 0x10000) ? 3 : 4; return l; };
根據(jù)上面的的代碼和UTF-8的編碼規(guī)范,我們就能夠很容易理解這種寬度計算的方法。
calculateUTF16asUTF8該方法是通過UTF16的數(shù)據(jù)來計算轉換為Unicode碼和轉換為UTF-8編碼后所占存儲長度。
/** * 根據(jù)UTF-16編碼的Bytes來計算轉換為Unicode的長度和轉換成UTF-8編碼后需要的存儲長度 * @param src 數(shù)據(jù)源,類型為Function,調(diào)用一次返回1 Byte數(shù)據(jù),如果到達字符串末尾則返回null */ utfx.calculateUTF16asUTF8 = function (src) { var n = 0, l = 0; utfx.UTF16toUTF8(src, function (cp) { ++n; l += (cp < 0x80) ? 1 : (cp < 0x800) ? 2 : (cp < 0x10000) ? 3 : 4; }); return [n, l]; };
該方法通過之前介紹的將UTF-16編碼轉換為Unicode碼的方法獲取到Unicode數(shù)據(jù),再進行計算,返回了Unicode碼的長度和UTF-8編碼后長度。
window.TextEncoder與Window.TextDecoder這是兩個處在實驗性的新構造函數(shù),通過創(chuàng)建編碼器(TextEncode對象)和解碼器(TextDecode對象)來實現(xiàn)JavaScript中string類型與UTF-8編碼數(shù)據(jù)中的互相轉換。
構造方法將會返回一個UTF-8編碼的,使用方法如下:
let encoder = new TextEncoder(); let decoder = new TextDecoder(); let unit8Array = encoder.encode("a"); // 返回一個Unit8Array類型——[97] let str = decoder.decode(arr); // 返回一個值為"a"的字符串
目前,這項新技術的的兼容性仍然存在很大問題,只有Chrome 38、Firefox 19以及Opera 25以上才支持,其他主流的瀏覽器如IE和Safari都還沒有任何支持,因此在生產(chǎn)環(huán)節(jié)中需要慎重使用。
總結本文對實現(xiàn)了Unicode中UTF-8和UTF-16這兩種編碼方式的庫——utfx.js進行了部分代碼分析。通過看到具體的代碼實現(xiàn),相信大家應該能夠更加好的理解這兩種編碼方式的具體規(guī)范,以及對應的使用方式和場景。
文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://systransis.cn/yun/94276.html
摘要:概念是一種針對的可變長度字符編碼,又稱萬國碼。通過上面的介紹我們可以知道,是一種非常通用的可變長字符編碼方式。概念是字符編碼五層次模型的第三層字符編碼表,也稱為的一種實現(xiàn)方式。 概述 本文通過介紹Unicode編碼以及對應的兩種編碼方式UTF-8和UTF-16,讓讀者能夠了解關于字符串編碼的相關知識,同時能夠弄清楚Unicode和UTF-8和UTF-16之間的關系。 本文的主要內(nèi)容為:...
摘要:總結通過使用和,我們能夠在數(shù)據(jù)和二進制數(shù)據(jù)中進行互相轉換。下一篇系列相關的博客,將會介紹如何通過來向后端傳遞二進制數(shù)據(jù),以及如何處理通過收到的二進制數(shù)據(jù)。 概述 上一篇博客我們說到了如何進行數(shù)字類型(如Short、Int、Long類型)如何在JavaScript中進行二進制轉換,如果感興趣的可以可以閱讀本系列第二篇博客——WebSocket系列之JavaScript中數(shù)字數(shù)據(jù)如何轉換為...
摘要:文章首發(fā)地址深入分析中的中文編碼問題背景編碼問題一直困擾著程序開發(fā)人員,尤其是在中更加明顯,因為是跨平臺的語言,在不同平臺的編碼之間的切換較多。 文章首發(fā)地址:深入分析 Java Web 中的中文編碼問題 背景: 編碼問題一直困擾著程序開發(fā)人員,尤其是在 Java 中更加明顯,因為 Java 是跨平臺的語言,在不同平臺的編碼之間的切換較多。接下來將介紹 Java 編碼問題出現(xiàn)的根本原...
閱讀 1834·2019-08-30 15:55
閱讀 1034·2019-08-26 11:57
閱讀 540·2019-08-26 11:29
閱讀 3378·2019-08-26 10:49
閱讀 1931·2019-08-23 18:40
閱讀 1837·2019-08-23 16:04
閱讀 3124·2019-08-23 11:01
閱讀 2299·2019-08-23 10:56