歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> 編碼 Unicode 及其在 JavaScript 中的使用

編碼 Unicode 及其在 JavaScript 中的使用

日期:2017/3/1 9:40:26   编辑:Linux編程

一、javascript 使用 unicode16 字符集,可以使用中文變量名和函數名

計算機使用 8 位(bit)二進制表示一個字節(Byte),計算機內存最小尋址單位就是 1 字節。早期為了在計算機上使用同一的方式使用字符,使用無符號整數來標記字符。

ANSI(美國國家標准局)制訂了ASCII(American Standard Code for Information Interchange,美國信息交換標准代碼),使用一個字節大小的二進制數來編碼每個字符。ASCII已經被國際標准化組織(ISO)定為國際標准,稱為ISO 646標准。

一個字節為8位二進制,2的8次方為256,因此有256個字符可以用一個字節來表示(0~255),但ASCII字符集只設計了128個字符(字母、數字、一些標點符號和控制字符),因此實際上只用到7位二進制,第八位設置為0,剩下的128個編碼位置是閒置的。

有的計算機廠商可能會利用閒置的128個空位來制訂一些字符的編碼,稱為OEM字符集。例如,IBM使用多出來的128位擴展了一個ASCII 擴展表,包含了一些控制符和制表符等等,被廣泛使用在電子元件的數據通訊和存儲中,但OEM字符集不是通用的標准。

為了編碼更多的字符,2個研究字符編碼的機構合並研究成果,制訂了 unicode 字符集。unicode 字符集使用使用多個字節來為字符編碼,按使用的字節數不同制訂了不同方案,所有 unicode 編碼方案前 1 個字節(256個碼位)的編碼對應的字符都是 ASCII 字符集中的字符。

目前 unicode 編碼已經達到 64 位,使用 8 個字節標記一個字符。

如果每個字符用2個字節(16位二進制數)來標記,可以編碼 65536 個字符(2 的16次方),這基本上已經可以標記世界上所有國家的語言符號,因此,在實際中通用的是UCS-2通用字符集(Universal Character Set,UCS),由ISO制定的ISO 10646(或稱ISO/IEC 10646)標准所定義。UCS 為第一字節的128個空位增補了一個字符集,稱為 C1控制符及拉丁文補充-1 (C1 Control and Latin 1 Supplement)。

UCS-2字符集編碼法有17個位面,每個位面都用2個字節來標記字符,17個位面可以映射 1,112,064個字符,其中最常用最重要的是編號為 0 的位面,裡面包含了最常用的字符編碼,稱為基本多國語言平面BMP(Basic Multilingual Plane)。

Unicode 第 0 平面(BMP)中的編碼被劃分為不同區段,各國文字符號、控制符、制表符、圖形字符等 都有連續的分布,其中中文簡繁體區段是 4E00-9FBF。

  • 0000-007F:C0控制符及基本拉丁文 (C0 Control and Basic Latin)  
  • 0080-00FF:C1控制符及拉丁文補充-1 (C1 Control and Latin 1 Supplement)  
  • 0100-017F:拉丁文擴展-A (Latin Extended-A)  
  • 0180-024F:拉丁文擴展-B (Latin Extended-B)  
  • 0250-02AF:國際音標擴展 (IPA Extensions)  
  • 02B0-02FF:空白修飾字母 (Spacing Modifiers)  
  • 0300-036F:結合用讀音符號 (Combining Diacritics Marks)
  • 4E00-9FBF:CJK 統一表意符號 (CJK Unified Ideographs)
  • (......還有很多國家語言和甲骨文等已經不用或極少使用的語言或字符的專用區段)

從第1位面開始,字符的unicode編碼已經超出16位二進制數的范圍,因此UCS-2無法使用2個字節直接編碼BMP位面之外的字符。但是,在 UCS-2 編碼中,區段 UD800 到 UDFFF 的碼位是閒置的保留位,因此,可以使用這個區段中的碼位通過一定的轉換方式映射到其他位面的 unicode 編碼。

在實際的字符傳輸和存儲行為中,為了節省字節數,可能不會直接傳輸 unicode 編碼,而是使用 Unicode轉換格式(Unicode Transformation Format,簡稱為UTF),目前常見的 UTF格式有UTF-7, UTF-7.5, UTF-8, UTF-16, 以及 UTF-32,他們是由 ITTF(Internet Engineering Task Force,互聯網工程任務組)組織進行標准化的,UTF-8 和 UTF-16 編碼使用比較廣泛。

UTF-16 編碼:該編碼法在 UCS-2 第0位面字符集的基礎上利用 D800-DFFF 區段的碼位通過一定轉換方式將超出2字節的字符編碼為一對16比特長的碼元(即32bit,4Bytes),稱作代理碼對 (surrogate pair)。

例如字符“”,他處於編號'2'的位面(總共17個位面,位面編號為16進制數0-10,第0位面可以捨去編號0直接用4位16進制數編碼),碼位是A6A5,即unicode編碼為 2A6A5,它在UTF-16中的代理碼對為 d869 dea5,但是通過 js 的charCodeAt()函數只能得出高位碼對,但是這並不影響解碼軟件對字符編碼進行定位,因為這些字符的代理碼對都是成對地分布在 UD800-UDFFF 區段內的,並不存在交叉的現象,知道高位碼對也可以簡單地搜索到低位碼對。

UTF-16 編碼出現以前,UD800-UDFFF 區段的碼位可能會被一些計算機產品設計者利用,而且其他位面的字符極少用到,因此,一些軟件可能無法正確識別代理碼對,這可能會導致一些BUG。例如,python 2.6 在 UNIX 平台上便無法正確識別代理碼對。如果一個軟件聲稱自己支持UCS-2,那麼他很可能是不支持UTF-16的。

javascript 跟 java 一樣使用UTF-16編碼,因此, 實際上 javascript 程序中變量名和函數名可以使用ASCII 之外的字符,例如中文,不過網頁文件保存的編碼格式要注意,使用的編碼格式對字符編碼的范圍應當不小於 UTF-16,比如保存為 utf-8 編碼。

  1. function試試看(){
  2. var打個招呼={你好:'好你妹!'};
  3. alert(打個招呼.你好);
  4. }
  5. 試試看();

二、字符編碼格式及其在 javascript 中的使用

1、unicode 16進制編碼

unicode 16 使用 16位二進制編碼字符,但是其編碼格式在書面上使用16進制(二進制寫起來太長了),在javascript中, \u 加 4個16進制字符表示一個字符的編碼(每個字節 8 位二進制對應2位十六進制,2^8 = 256 = 16^2),不足4位16進制的,高位用0補足,比如 \u55B5 表示漢字 "喵",字母 "a" 的 ASCII 碼是10進制 97,表示成 16 進制 unicode 編碼格式就是 \u0061。試試打印出來:

  1. document.write('\u55B5');
  2. document.write('\u0061');

2、javascript charCodeAt 和 String.fromChartCode 使用 10 進制編碼

在 javascript 字符串的 charCodeAt 和 String.fromChartCode 中取得和使用的字節編碼都是 10 進制的,因此在 document.write 和 這些方法配合使用時需要進行進制轉換。
另外要注意的是,如果一個變量保存了一個字符的 unicode() 編碼,你想用 document.write() 打印到頁面上就需要注意了,不要將'\u' 轉義成 '\\u' ,如果轉義了,需要使用 eval() 來執行,否則將直接把編碼打印出來:

  1. var code1 ='\\u0061';
  2. document.write(code1);// \u0061
  3. var code2 ='\u0061';
  4. document.write(code2);// a

但是在表達式中,也許你想拼接出 unicode 編碼後打印字符串,這就要注意了,因為在字符串中 \u 後面必須接 4個十六進制字符才是合法的語法,所以不得不轉義:

  1. var code ="\\u"+("0000"+('a').charCodeAt(0).toString(16)).slice(-4);
  2. document.write(code);// \u0061
  3. document.write(eval('"'+code+'"'));//正確做法 ,注意eval 時加上引號,因為 document.write 接受的參數是字符串,document.write("\u0061"),其中 \u0061 是單個字符,而不是可以分割的多個字符組成的字符串 ( "\\"+"u"+"0061" ), 而形如document.write(\u0061) 的語句是個語法錯誤.

試試下面代碼

  1. function \u0061(){ console.log(123)}
  2. \u0061();
  3. a();

3、javascript 中的單字節編碼

在 js 中,可以使用 \x 加 2位16進制字符標記一個單字節的字符,例如字符 'a' 可以表示為 \x61,用法類似\u 加4位16進制編碼。

  1. document.write('\x61');// a

\u 加四位十六進制數 或 \x 加2位十六進制數屬於轉義字符,在 js 字符串長度中只算 1 個,轉義字符不能直接用於 HTML 文件(不會轉換後輸出,而是直接輸出轉義格式的字符串),但可以用 document.write()打印出來,因為在 js 語法范圍內,雖然表達方式不一樣,但是轉義字符和直接的字符字面量都是指同一個東西:

  1. console.log("\u0061"==='a');//true
  2. ('123|u55b5abc').length //12
  3. ('123|u55b5abc').split('')//["1", "2", "3", "|", "u", "5", "5", "b", "5", "a", "b", "c"]
  4. ('123\u55b5abc').length //7
  5. ('123\u55b5abc').split('')// ["1", "2", "3", "喵", "a", "b", "c"]

4、 xss 與 字符編碼

當向頁面顯示用戶輸入的內容是,通常我們要過濾或轉義 script 標簽以避免 XSS 攻擊,

但是,需要注意的是, \u+16進制 、\x+16進制 、字符實體如果出現在模板中的 HTML 標簽屬性中就需要特別注意了,他們會正確解碼後才賦給標簽的屬性,例如:

  1. document.body.innerHTML ='<img src="wrongUrl.gif" onerror="&#116;&#104;&#105;&#115;&#46;&#115;&#114;&#99;&#61;&#39;&#104;&#116;&#116;&#112;&#58;&#47;&#47;&#119;&#119;&#119;&#46;&#120;&#115;&#115;&#46;&#99;&#111;&#109;&#39;" >';

對標簽屬性之進行轉義時,需要對注意,是比較下面2個做法:

  1. document.body.innerHTML ='<a onclick="\&\#116;\&\#104;\&\#105;\&\#115;">click me</a>';
  2. document.body.innerHTML ='<a onclick="\\&\\#116;\\&\\#104;\\&\\#105;\\&\\#115;">click me</a>';

5、八進制轉義字符

js 字符串中,\ 開始後接正數,可能被解析為8進制轉義字符。

一個八進制轉義字符形成的條件是:斜線後面接的整數最長3位,至少1位,單個數字的字面值不大於8。

如果過不滿足任意一項,都將結束一個字符的解釋,開始新字符的解釋。八進制轉義字符的10進制數字字面值最大值為377,即 '\377' 被解析為一個字符,'\378' 被解析為2個字符: '\37' 和 '8' :

  1. '\377'.length //1
  2. console.log('\377')// ÿ
  3. '\378'.length //2
  4. '\128'.length //2
  5. console.log('\127')//W
  6. 'W'.charCodeAt(0)//87
  7. (87).toString(8)//'127'

更多詳情見請繼續閱讀下一頁的精彩內容: http://www.linuxidc.com/Linux/2014-09/106211p2.htm

Copyright © Linux教程網 All Rights Reserved