JS中unicode和utf-8的轉換


JS中unicode和utf-8的轉換

最近公司找了幾個py寫后端項目,后端接口中返回 '\xe6\x88\x91\xe4\xbb\xac' 類似的編碼,我看着就很好奇,於是將此段編碼過的字符輸入chrome的控制台,結果如下:

> '\xe6\x88\x91\xe4\xbb\xac'
< "我们"

很明顯,由於解釋錯誤出現了亂碼問題。。。

在網上一番搜索發現,這就是utf-8編碼,本着好奇,就想知道unicode和utf-8之間是如何轉換的。。。至於utf-8和unicode的區別,我只強調一點 UTF-8是 Unicode 的實現方式之一 ,具體的話大家網上自行查找,這里提供我參考的文章 字符編碼筆記:ASCII,Unicode 和 UTF-8,下面我總結下在js中這兩種編碼之間如何轉換

unicode轉utf-8

我們知道在js中,encodeURI和encodeURIComponent函數將URI轉為utf-8編碼:

> encodeURIComponent('深圳華強')
< "%E6%B7%B1%E5%9C%B3%E5%8D%8E%E5%BC%BA"

在網上驗證下沒問題:

/**
* 
* @param str {String}
* @return {Array{Number}}
*/
function encodeUTF8 (str = '深圳華強') {
    let str1 = encodeURIComponent(str) // "%E6%B7%B1%E5%9C%B3%E5%8D%8E%E5%BC%BA"

    let ret = []

    for (let i = 0; i < str1.length / 3; i++) {
      ret.push(str1.slice(i * 3, (i + 1) * 3).slice(1))
    }

     // ret = ["E6", "B7", "B1", "E5", "9C", "B3", "E5", "8D", "8E", "E5", "BC", "BA"]

    return ret.map(el => parseInt(el, 16)) // [230, 183, 177, 229, 156, 179, 229, 141, 142, 229, 188, 186]
  }

utf-8轉unicode

/**
* 
* @param arr {Array{Number}}
* @return {string}
*/
function decodeUTF8 (arr = [230, 183, 177, 229, 156, 179, 229, 141, 142, 229, 188, 186]) {
  let str = arr.reduce((prev, cur) => prev +=`%${cur.toString(16)}`, '')

  return decodeURIComponent(str) // '深圳華強'
}

測試

> encodeUTF8()
< [230, 183, 177, 229, 156, 179, 229, 141, 142, 229, 188, 186]

> decodeUTF8()
< "深圳華強"

最后回到我們開頭的問題, '\xe6\x88\x91\xe4\xbb\xac' 到底代表什么意思?

我嘗試很很多種方法,發現只要js識別到 '\xe6\x88\x91\xe4\xbb\xac' 馬上就進行解碼了,根本沒有機會操作。。。最后我發現將其中\要先轉義處理:'\xe6\x88\x91\xe4\xbb\xac',然后就好處理了,如果這個東西要前端要展示的話,只能暫時求助后端同學提前對反斜杠進行轉移處理了。。。

let reg = /\\x/g
console.log('\\xe6\\x88\\x91\\xe4\\xbb\\xac') // \xe6\x88\x91\xe4\xbb\xac
console.log('\\xe6\\x88\\x91\\xe4\\xbb\\xac'.replace(reg, '%')) // %e6%88%91%e4%bb%ac
console.log(decodeURIComponent('\\xe6\\x88\\x91\\xe4\\xbb\\xac'.replace(reg, '%'))) // 我們

續更(2020.7.21)

對於昨天結尾遺留的問題,我找到了不完美的解決方案:ECMAScript 6 入門 String.raw()
ES6 還為原生的 String 對象,提供了一個raw()方法。該方法返回一個斜杠都被轉義(即斜杠前面再加一個斜杠)的字符串,往往用於模板字符串的處理方法

String.raw`Hi\n${2+3}!`
// 實際返回 "Hi\\n5!",顯示的是轉義后的結果 "Hi\n5!"

String.raw`Hi\u000A!`;
// 實際返回 "Hi\\u000A!",顯示的是轉義后的結果 "Hi\u000A!"

解決方案跟昨天后端童鞋解決方案一樣,通過 String.raw 對反斜杠\進行轉義,如下:

let reg = /\\x/g
let str = String.raw`\xe6\x88\x91\xe4\xbb\xac`
// 實際返回 "\\xe6\\x88\\x91\\xe4\\xbb\\xac",顯示的是轉義后的記過 "\xe6\x88\x91\xe4\xbb\xac"
// 后續的操作就跟上邊一樣了,String.raw缺陷就是沒辦法傳入變量...

let str = '\xe6\x88\x91\xe4\xbb\xac'
String.raw`${str }`
// 返回 "我们" 相當於還是解析str了,導致String.raw失效了

參考資料:
UTF-8編碼規則(轉)
rfc3629
查看字符編碼(UTF-8)在線工具
字符編碼的前世今生
兩次encodeURI和URLDecode的原理分析
JavaScript進行UTF-8編碼與解碼


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM