轉載請註明文章出處: https://tlanyan.me/string-uni...
想知道某個字符串的UTF8編碼,圖方便打算使用在線工具。坑爹的是,號稱「UTF8漢字互轉」的網頁幾乎全是字符串和unicode碼點互轉,並不提供與UTF8編碼互轉功能。沒搞懂unicode碼點(code point)和UTF8編碼的關係,還大言不慚的說UTF8編碼,真讓人無語。app
字符、字節和字節序,unicode和UTF8編碼,是理解字符編碼重要的概念,詳情可查看本人以前博文文件和字符編碼。本文討論unicode和UTF8之間的轉換,先簡要介紹兩個概念:unicode是將字符與碼點(code point,一個整數)一一對應的編碼方案;碼點一般用uXXXX或者U+XXXX的方式表示,XXXX是碼點的十六進制;UTF8是unicode的一個具體編碼方案,規定字符存儲的方式;UTF8編碼字節數可變,不存在大小端問題,互聯網通訊中常採用此種編碼方式。函數
回顧一下那成片的「漢字UTF8編碼互轉」網頁所作的事情。以「中國」爲例,兩個漢字碼點分別爲20013和22269,十六進制表示4E2D 56FD,UTF8編碼E4 B8 AD E5 9B BD。隨手打開搜索結果中的http://www.ip138.com/utf8/,輸入「中國」,點擊「轉換UTF-8」按鈕,下方出現碼點的十六進制編碼4E2D 56FD(能夠理解爲十六進制的前綴0x),並不是UTF8編碼。工具
JavaScript的String對象有charCodeAt
和codePointAt
(兼容性不如charCodeAt)方法。根據這個函數,網頁的轉換工做可用以下代碼實現:編碼
function encode(str) { var result = ''; var len = str.length; for (var i = 0; i < len; ++ i) { result += '&#x' + (str.charCodeAt(i)).toString(16) + ';'; // 轉換成16進制,並增長分隔符 } return result; } function decode(str) { return String.fromCharCode.apply(null, str.split(';').map(function(un) { return parseInt(un.replace('&#x', ''), 16); // 移除分隔符,轉換成碼點 }).filter(function (num) { return !isNaN(num); })); }
調用encode(「中國」)
或者其餘字符串,將獲得每一個字符對應碼點的十六進制。但這不是字符串的UTF8編碼!spa
要拿到UTF8編碼,須要在碼點的基礎上多走一步。先回顧unicode碼點與UTF8的轉換關係:code
unicode碼點(十六進制) | UTF-8(二進制) |
---|---|
0000 0000-0000 007F | 0xxxxxxx |
0000 0080-0000 07FF | 110xxxxx 10xxxxxx |
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx |
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
根據這個表,結合charCodeAt
函數,能夠寫出字符串到UTF8編碼的函數:對象
// 獲取字符串的utf8字節流 function getUTF8Bytes(str) { var bytes = []; var len = str.length; for (var i = 0; i < len; ++ i) { var code = str.charCodeAt(i); if (code >= 0x10000 && code < = 0x10ffff) { bytes.push((code >> 18) | 0xf0); // 第一個字節 bytes.push(((code >> 12) & 0x3f) | 0x80); bytes.push(((code >> 6) & 0x3f) | 0x80); bytes.push((code & 0x3f) | 0x80); } else if (code >= 0x800 && code < = 0xffff) { bytes.push((code >> 12) | 0xe0); bytes.push(((code >> 6) & 0x3f) | 0x80); bytes.push((code & 0x3f) | 0x80); } else if (code >= 0x80 && code < = 0x7ff) { bytes.push((code >> 6) | 0xc0); bytes.push((code & 0x3f) | 0x80); } else { bytes.push(code) } } return bytes; } // 將字節流轉換成16進制字符串 function hexString(bytes) { var arr = bytes.map(function (code) { return (code).toString(16).toUpperCase(); }); return arr.join(' '); } function utf8(str) { return hexString(getUTF8Bytes(str)); }
調用函數utf8
,這纔是JavaScript獲得字符串的UTF8編碼的正確姿式!從UTF8編碼轉換到字符串,作相反工做便可。ip