通過javascript進行UTF-8編碼

来源:http://www.cnblogs.com/doublenet/archive/2016/06/25/5616451.html
-Advertisement-
Play Games

通過javascript進行UTF 8編碼 javascript的字元集: javascript程式是使用 字元集編寫的。 是`ASCII Latin 1 ECMAScript3 Unicode2.1 ECMAScript5 Unicode3`及後續版本。所以,我們編寫出來的javascript程式 ...


通過javascript進行UTF-8編碼


javascript的字元集:

javascript程式是使用Unicode字元集編寫的。UnicodeASCIILatin-1的超集,並支持地球上幾乎所有的語言。ECMAScript3要求JavaScript必須支持Unicode2.1及後續版本,ECMAScript5則要求支持Unicode3及後續版本。所以,我們編寫出來的javascript程式,都是使用Unicode編碼的。

UTF-8

UTF-8(UTF8-bit Unicode Transformation Format)是一種針對Unicode的可變長度字元編碼,也是一種首碼碼。

它可以用來表示Unicode標準中的任何字元,且其編碼中的第一個位元組仍與ASCII相容,這使得原來處理ASCII字元的軟體無須或只須做少部分修改,即可繼續使用。因此,它逐漸成為電子郵件、網頁及其他存儲或發送文字的應用中,優先採用的編碼

目前大部分的網站,都是使用的UTF-8編碼。

將javascript生成的Unicode編碼字元串轉為UTF-8編碼的字元串

如標題所說的應用場景十分常見,例如發送一段二進位到伺服器時,伺服器規定該二進位內容的編碼必須為UTF-8。這種情況下,我們必須就要通過程式將javascript的Unicode字元串轉為UTF-8編碼的字元串。

轉換方法

轉換之前我們必須瞭解Unicode的編碼結構是固定的。
不信可以試一試 String 的 charCodeAt 這個方法,看看返回的 charCode 占幾個位元組。

  • 英文占1個字元,漢字占2個字元

然而,UTF-8的編碼結構長度是根據某單個字元的大小來決定長度有多少。
下麵為單個字元的大小占用幾個位元組。單個unicode字元編碼之後的最大長度為6個位元組。

  • 1個位元組:Unicode碼為0 - 127
  • 2個位元組:Unicode碼為128 - 2047
  • 3個位元組:Unicode碼為2048 - 0xFFFF
  • 4個位元組:Unicode碼為65536 - 0x1FFFFF
  • 5個位元組:Unicode碼為0x200000 - 0x3FFFFFF
  • 6個位元組:Unicode碼為0x4000000 - 0x7FFFFFFF

具體請看圖片:
圖片描述

因為英文和英文字元的Unicode碼為0 - 127,所以英文在Unicode和UTF-8中的長度和位元組都是一致的,只占用1個位元組。這也就是為什麼UTF8是Unicode的超集

現在我們再來討論漢字,因為漢字的unicode碼區間為0x2e80 - 0x9fff, 所以漢字在UTF8中的長度最長為3個位元組。

那麼漢字是如何從Unicode的2個位元組轉換為UTF8的三個位元組的哪?

假設我需要把漢字"中"轉為UTF-8的編碼

1、獲取漢字Unicode值大小

var str = '中';
var charCode = str.charCodeAt(0);
console.log(charCode); // => 20013

2、根據大小判斷UTF8的長度

由上一步我們得到漢字"中"的charCode為20013.然後我們發現20013位於2048 - 0xFFFF這個區間里,所以漢字"中"應該在UTF8中占3個位元組。

3、補碼

既然知道漢字"中"需要占3個位元組,那麼這3個位元組如何得到哪?

這就需要設計到補碼,具體補碼邏輯如下:
圖片描述
好吧,我知道這個圖你們也看不明白,還是我來講吧!

具體的補位碼如下,"x"表示空位,用來補位的。

  • 0xxxxxxx
  • 110xxxxx 10xxxxxx
  • 1110xxxx 10xxxxxx 10xxxxxx
  • 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
  • 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
  • 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

warning:有沒有發現?補位碼第一個位元組前面有幾個1就表示整個UTF-8編碼占多少個位元組!UTF-8解碼為Unicode就是利用的這個特點哦~

我們先舉個簡單的例子。把英文字母"A"轉為UTF8編碼。
1、“A”的charCode為65
2、65位於0-127的區間,所以“A”占一個位元組
3、UTF8中一個位元組的補位為0xxxxxxx,x表示的是空位,是用來補位的。
4、將65轉為二進位得到1000001
5、將1000001按照從前到後的順序,依次補到1xxxxxxx的空位中,得到01000001
6、將11000001轉為字元串,得到"A"
7、最終,"A"為UTF8編碼之後“A”

通過這個小例子,我們是否再次驗證了UTF-8是Unicode的超集

好了,我們現在再回到漢字"中"上,之前我們已經得到了"中"的charCode為20013,二進位為01001110 00101101。具體如下:

var code = 20013;
code.toString(2); 
// => 100111000101101 等同於 01001110 00101101

然後,我們按照上面“A”補位的方法,來給"中"補位。
01001110 00101101按照從前到後的順序依此補位到1110xxxx 10xxxxxx 10xxxxxx上.得到11100100 10111000 10101101.

4、得到UTF8編碼的內容

通過上面的步驟,我們得到了"中"的三個UTF8位元組,11100100 10111000 10101101
我們將每個位元組轉為16進位,得到0xE4 0xB8 0xAD;
那麼這個0xE4 0xB8 0xAD就是我們最終得到的UTF8編碼了。

我們使用nodejs的buffer來驗證一下是否正確。

var buffer = new Buffer('中'); 
console.log(buffer.length); // => 3
console.log(buffer); // => <Buffer e4 b8 ad>
// 最終得到三個位元組 0xe4 0xb8 0xad

因為16進位是不分大小寫的,所以是不是跟我們算出來0xE4 0xB8 0xAD一模一樣。

將上面的編碼邏輯寫到一個函數中。

// 將字元串格式化為UTF8編碼的位元組
var writeUTF = function (str, isGetBytes) {
      var back = [];
      var byteSize = 0;
      for (var i = 0; i < str.length; i++) {
          var code = str.charCodeAt(i);
          if (0x00 <= code && code <= 0x7f) {
                byteSize += 1;
                back.push(code);
          } else if (0x80 <= code && code <= 0x7ff) {
                byteSize += 2;
                back.push((192 | (31 & (code >> 6))));
                back.push((128 | (63 & code)))
          } else if ((0x800 <= code && code <= 0xd7ff) 
                  || (0xe000 <= code && code <= 0xffff)) {
                byteSize += 3;
                back.push((224 | (15 & (code >> 12))));
                back.push((128 | (63 & (code >> 6))));
                back.push((128 | (63 & code)))
          }
       }
       for (i = 0; i < back.length; i++) {
            back[i] &= 0xff;
       }
       if (isGetBytes) {
            return back
       }
       if (byteSize <= 0xff) {
            return [0, byteSize].concat(back);
       } else {
            return [byteSize >> 8, byteSize & 0xff].concat(back);
        }
}

writeUTF('中'); // =>  [0, 3, 228, 184, 173] 
// 前兩位表示後面utf8位元組的長度。因為長度為3,所以前兩個位元組為`0,3`
// 內容為`228, 184, 173`轉成16進位就是`0xE4 0xB8 0xAD`
// 讀取UTF8編碼的位元組,並專為Unicode的字元串
var readUTF = function (arr) {
    if (typeof arr === 'string') {
        return arr;
    }
    var UTF = '', _arr = this.init(arr);
    for (var i = 0; i < _arr.length; i++) {
        var one = _arr[i].toString(2),
                v = one.match(/^1+?(?=0)/);
        if (v && one.length == 8) {
            var bytesLength = v[0].length;
            var store = _arr[i].toString(2).slice(7 - bytesLength);
            for (var st = 1; st < bytesLength; st++) {
                store += _arr[st + i].toString(2).slice(2)
            }
            UTF += String.fromCharCode(parseInt(store, 2));
            i += bytesLength - 1
        } else {
            UTF += String.fromCharCode(_arr[i])
        }
    }
    return UTF
}

readUTF([0, 3, 228, 184, 173]); => '中'

另外一種將中文解析得到UTF8位元組碼的方法

另外一種比較簡單的將中文轉為UTF8位元組碼的方法比較簡單,瀏覽器也提供了一個方法,而且這個方法大家都一直在用,是什麼哪?就是encodeURI。當然,encodeURIComponent也是可以的。
沒錯,就是這個方法。那麼這個方法是怎麼將一個Unicode編碼的中文轉為UTF8的位元組碼嘞?

var str = '中';

var code = encodeURI(str);

console.log(code); // => %E4%B8%AD

有沒有發現得到了一個轉義後的字元串,而且這個字元串中的內容和我之前在上面得到的位元組碼是一樣的~~~。

下麵我們將%E4%B8%AD轉為一個number數組。

var codeList = code.split('%');

codeList = codeList.map(item => parseInt(item,16));

console.log(codeList); // => [228, 184, 173]

如此簡單,有木有~~~

這個簡便方法的原理是什麼?

這裡就涉及到的URI中的querystring編碼的問題了。因為按照規定,URI中的querystring必須按照UTF8的編碼進行傳輸,而JavaScript是Unicode的,所以瀏覽器就給我們提供了一個方法,也就是encodeURI/encodeURIComponent方法。這個方法會講非英文字元(這裡考慮下,為什麼是非英文字元?)先轉為UTF8的位元組碼,然後前面加個%進行拼接,所以我們將漢字"中"轉義下便得到了"%E4%B8%AD".
好吧,原理就這些,沒有其他的了。

不過,這種方法還有個缺點,那就是只會轉義非英文字元,所以當我們需要將英文字元也格式化為UTF8編碼時,這個方法是達不到我們需求的,我們還需要額外的將英文字元也給轉義下。

那我想要解析回來應該怎麼做哪?用decodeURI/decodeURIComponent就可以了。

var codeList = [228, 184, 173];

var code = codeList.map(item => '%'+item.toString(16)).join('');

decodeURI(code); // => 中

好了,到這裡本文也就介紹完UTF8的編碼了。
希望可以幫助大家瞭解到UTF-8編碼的原理。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 兩個數組合併與最大值最小值的獲取 //示例二 獲取最大值, var numbers = [5, 458, 120, -215]; var maxInNumbers = Math.max.apply(Math, numbers); //458 console.log("maxInNumbers:" + ...
  • × 目錄 [1]邏輯非 [2]邏輯與 [3]邏輯或 前面的話 邏輯運算符對操作數進行布爾運算,經常和關係運算符一樣配合使用。邏輯運算符將多個關係表達式組合起來組成一個更複雜的表達式。邏輯運算符分為邏輯非'!'、邏輯與'&&'、邏輯或'||'3種,本文將介紹這三種邏輯運算符 邏輯非 邏輯非操作符由一個 ...
  • HTML經過10多年的發展,其元素經歷了廢棄與不斷重新定義的過程。為了更好的處理現在的互聯網應用,HTML5新增了圖形繪製、多媒體播放、頁面結構、應用程式存儲、網路工作等新元素。http://hovertree.com/menu/html5/ 圖形繪製新元素 標簽描述 <canvas> 標簽定義圖形 ...
  • HTML5簡介 HTML5是HTML的最新修訂標準。2014年10月29日,萬維網聯盟(W3C)宣佈,經過8年的努力,HTML5標準規範制定完成。 HTML5的設計目的是在移動設備上使用多媒體。 HTML5簡單易學。 http://hovertree.com/menu/html5/ 什麼是HTML5 ...
  • × 目錄 [1]定義 [2]應用場景 [3]轉為布爾[4]實例方法 前面的話 布爾值Boolean類型可能是三種包裝對象Number、String和Boolean中最簡單的一種。Number和String對象擁有大量的實例屬性和方法,Boolean卻很少。從某種意義上說,為電腦設計程式就是與布爾值 ...
  • 1、HTML5不支持或不贊成使用的標簽 <acronym>——定義只取首字母的縮寫,HTML5 不支持。使用<abbr>定義縮寫代替,其中title 屬性可用於在滑鼠指針移動到元素上時顯示出縮寫的完整版本,堅持寫上title,這樣對瀏覽器和搜索引擎都比較友好。 <applet>——定義嵌入的 app ...
  • 在不同瀏覽器查看代碼效果可謂是家常便飯,所以用不同快捷鍵打開相應瀏覽器可以大大提高工作效率。工欲善其事,必先利其器啊,沒設置看文章吧,非常簡單。 ...
  • CSS樣式規範 1.類選擇器 2.標簽選擇器 3.id選擇器 4.CSS樣式的子選擇器 類選擇器 1.必背的固定結構,成為CSS樣式標記。所有的樣式都可以寫成CSS樣式的標記中 <style type="text/css"> </style> 2. type=“text/css” 意思是聲明這個標記 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...