[web] 瞭解網頁中看不懂的編碼:Unicode 在JavaScript 中的使用

文章推薦指數: 80 %
投票人數:10人

你可以發現在ASCII 中定義了127 個文字符號和數字之間的關係,但是那是因為英文只需要有26 個英文字母就可以組成各是各樣的單字,但是中文或者說許多國家 ... 跳至主要内容這個網站放置的是未發佈或未完整整理的筆記內容,若想檢視正式的筆記內容請到PJCHENder那些沒告訴你的小細節。

PJCHENderOfficialDocsBlogGitHubFacebookLinkedin搜尋WebDev[web]Unicode本頁導覽keywords:unicode,utf-8,JavaScript如果只是想要簡單知道Unicode是什麼,沒有要瞭解使用方式的話,可以觀看計算機科學速成課(第四集):二進制,在此教學影片的後半段有提到文字符號的編碼概念。

在學習網頁開發的過程中,一定會慢慢的碰到所謂的Unicode,UTF-8還有其他幾種不同的編碼方式,這麼說你可能不會太有感覺,讓我們以Facebook為例,你可以看到在資料傳遞的過程中,常常有這種看不太懂的東西...我們把它拿出來編排一下大概長這樣:"profiles":{"768320183253420":{"name":"PJCHENder\u7db2\u9801\u524d\u7aef\u8cc7\u6e90\u7ad9","firstName":"PJCHENder\u7db2\u9801\u524d\u7aef\u8cc7\u6e90\u7ad9","gender":11,"uri":"https:\/\/www.facebook.com\/pjchender\/","type":"page","businessID":0,"businessName":null,"allBusinessData":[{"businessID":0,"businessName":null}]},//...}你可以看到裡面有\u7db2\u9801\u524d\u7aef\u8cc7\u6e90\u7ad9這種看不太懂的內容。

再舉一個例子來看,有些時候我們可能看到某些網路文章想要分享給別人,明明網址是:https://today.line.me/tw/pc/article/冰火之國+冰島-ownNlj,可是一分享出去卻變成一堆看似亂碼的東西https://today.line.me/tw/pc/article/%E5%86%B0%E7%81%AB%E4%B9%8B%E5%9C%8B+%E5%86%B0%E5%B3%B6-ownNlj:上面的這些例子都是文字轉成編碼後的情況,你應該可以瞭解到這些編碼在瞭解網頁開發時的重要性的,如果不懂的話,就無法把這些內容解碼回去,那就會看不懂別人的內容阿...看到編碼卻不知道怎麼解碼,那該怎麼上車呢?在這篇文章中會說明在網頁中常用的一些編碼方式,讓對網頁編碼沒有概念的捧油們可以對它有些概念,重點是對它不再畏懼,然後有興趣的話可以在透過延伸閱讀中的文章進一步瞭解更多細節。

什麼是字串編碼(StringEncode)?​先來談談什麼是字串編碼,字串編碼簡單來說,就是把我們熟悉的文字用許多數字來代表它,你可以想像就像在當兵或坐牢的時候,大家不會直接叫你的名字,而是叫你的編號。

例如,「阿童」在坐牢時的編號是「9453」,這時候只要廣播「9453」請到司令台集合,阿童就會知道這是在叫他,就會跑到司令台來了。

這個編號是不會重複的,也就是「9453」就只會是「阿童」的編號,不會同時有其他淡水阿婆、基隆阿公的編號也一樣是9543。

能夠代表你的身份證字號也是一種編碼的概念,這個編號就可以用來代表它指稱的是你。

電腦只認得數字​接著你可能會好奇,在監獄裡面因為方便管理、去個人化等因素,所以把人名改成編碼似乎合理,但為什麼需要把我們常用的文字也都變成編碼呢?這是因為電腦在運算的過程中,底層都還是數字來表示的,電腦只看得懂數字,但並不認得文字符號。

也就是它只看的懂「9453」這個數字,但並不認得「阿童」這些字。

更精確的說,電腦只認得「二進制」這種用0和1組成的數字。

由於電腦只認得數字,但是我們人類看得懂、使用的卻是文字,那麼該怎麼辦呢?於是,美國最早定義了一套文字符號的編碼,能夠將每個英文的文字符號(Symbol)都對應到一個數字,這個最早統一的規定就稱為「ASCII編碼」。

文字符號(Symbol)指的是可以把文字拆成的最小單位,像是英文的「字母」a,b,c都是文字符號;而中文的「國字」,像是人,國,正這些也都是文字符號。

ASCII編碼(ASCIICode)​ASCIICode是由美國制訂,最早用來統一英文文字符號和數字間的對應關係,除了52個大小寫英文字母外,其中也包含了常用的符號(如!,)​在瞭解不同數值間的進位制轉換後,來看看一般會怎麼樣來表示Unicode的數值。

前面提到過Unicode就像一個世界通用的大字典,收納了好幾百萬個全世界的文字符號,且每一個文字符號都有一個屬於自己的編號。

而一般在Unicode中我們會用十六進制來表示某一個文字符號的編號,並且使用U+的方式來表示,例如U+0061就表示英文字母的a,其中的0061是十六進位制的數值,轉換成10進位的話是97,你可以發現這和當初的ASCII表示相對應的:Number('0x0061');//回傳97,將十六進制的0061轉成10進制又例如,阿童的「阿」用Unicode來表示是U+963f,「童」則是可用UnicodeU+7ae5表示。

碼點(CodePoint)​概念上,我們會把這些文字符號所對應到的編號,稱作是「碼點(CodePoint)」,又稱作「編碼位置」。

在Unicode中指的是U+後面的十六進制數值,每個碼點都是唯一的。

例如a的碼點是0061,「阿」的碼點是963f,「灣」的碼點是7ae5。

根據碼點的編號範圍,又可以分成「基本平面」和「輔助平面」。

基本名面和輔助平面​Unicode編碼中碼點的可能範圍從U+0000一直到U+10FFFF超過110萬個文字符號,因此又可分為基本平面(BMP,BasicMultilingualPlane)和輔助平面(SMP,SupplementaryplanesorAstralplanes)。

基本平面(BMP):碼點位置範圍從U+0000到U+FFFF,這個平面放了最常見的文字符號。

輔助平面(SMP):碼點位置範圍從U+010000一直到U+10FFFF,又稱為補充平面。

此外,原本ASCII中數字和文字符號的對應關係,可以直接沿用到Unicode中,也就是ASCII中a的編號會和Unicode中a的編號相同。

JavaScript中提供的相關函式​keywords:String.fromCodePoint(),String.prototype.codePointAt()​若想要查看某一個字的Unicode碼點,或者根據碼點反查是某一個字,在JavaScriptES6提供了String.fromCodePoint(),String.prototype.codePointAt()這兩個函式,讓你可以在Unicode碼點和文字符號間相互轉換。

str.codePointAt()和String.fromCodePoint()是ES6提供的函式,若要對應回ES5的用法,則分別是對應回str.charCodeAt()和String.fromCharCode()。

大部分的情況下ES5和ES6會得到一樣的結果,但若有使用到輔助平面文字符號(U+010000以上)時ES5則可能會產生錯誤,因此建議在支援ES6的情況下,使用ES6的函式以避免錯誤發生。

文字符號-->Unicode碼點(10進位)​透過String.prototype.codePointAt()可以將一個文字符號轉換成Unicode碼點,但回傳的是十進位,因此一般會需要轉成16進位來表示://文字符號-->Unicode碼點(10進位)String.prototype.codePointAt()//ES6提供的方法'A'.codePointAt()//回傳'65'(這是十進制)(65).toString(16)//回傳41,將65轉成十六進制後,表示A為U+0041//也可以一次把它轉成16進制'A'.codePointAt().toString(16)//'41',表示A=U+0041'童'.codePointAt().toString(16)//'7ae5',表示童=U+7ae5'💩'.codePointAt().toString(16)//'1f4a9',表示💩=U+1f4a9Unicode碼點-->文字符號​使用JavaScriptES6的方法String.formCodePoint()則可以把碼點轉換為文字符號。

如同前面文章「不同進位制的表示」所述,數字在表示時若為16進位,則開頭需加上0x來表示://Unicode碼點->文字符號String.fromCodePoint([,...[,numN]])//ES6提供的方法String.fromCodePoint(65)//A,使用10進位String.fromCodePoint(0x0041)//A,使用16進位String.fromCodePoint(0o101)//A,使用8進位在JavaScript字串中顯示Unicode字元​除了透過String.formCodePoint()這種方式來將Unicode碼點轉換為文字符號外。

在JavaScript中,可以直接使用console.log()函式就能將Unicode轉換成文字符號顯示出來。

其中根據不同的適用時機或場合有幾種不同的表示方式,包括:只使用到Unicode基本平面時(\u)有使用到Unicode輔助平面時(\u{})只使用到ASCII字符時(\x)只使用到Unicode基本平面時(\\u)​使用:\u適用範圍:Unicode基本平面字符,也就是U+0000到U+FFFF。

console.log('\u0041\u0042\u0043');//'ABC''臺'==='\u81fa';//trueconsole.log('\u81fa');//臺console.log('\u81fa\u7063');//臺灣console.log('\u2661\u81fa\u7063');//'♡臺灣'❗若在\u使用了輔助平面文字符號的碼點時會產生錯誤的結果。

有使用到Unicode輔助平面時(\\u{碼點})​使用:\u{碼點}適用範圍:所有Unicode字元,特別是有使用超過U+FFFF的輔助平面文字符號為了支援輔助平面的字元,在JavaScriptES6中引進了新的Unicode碼點跳脫序列(Unicodecodepointescapes),透過將碼點放在大括號{}內,也就是\u{碼點}就能正確識別,許多常見的emoji符號都是屬於輔助平面內的文字符號://使用2位數的十六進制(一個位元組)console.log('\u{41}\u{42}\u{43}');//'ABC'//使用4位數的十六進制(兩個位元組)console.log('\u{0041}\u{0042}\u{0043}')//ABC//使用超過4位數以上的十六進制console.log('\u{1F4A9}');//'💩'U+1F4A9console.log('\u{1F923}');//'🤣'U+1F923console.log('\u{1F436}')//'🐶'U+1F436只使用到ASCII字符時(\\x)​使用:\x適用範圍:U+0000到U+00FF,只用到Unicode兩位數的十六進制時,也就是一個位元組時舉例來說,U+0041=\x41console.log('\x41\x42\x43');//'ABC'統整一下​A=U+0041=\x41=\u0041=\u{41}=\u{0041}也就是下面會得到一樣的結果console.log('\x41');//'A'console.log('\u0041');//'A'console.log('\u{41}');//'A'console.log('\u{0041}');//'A'在CSS中使用Unicode​如果想要在CSS中使用Unicode,可以使用前輟\來進行跳脫:.content{display:inline-block;background-color:steelblue;padding:100px;color:white;}.content::before{content:'\0041';//A,輸入16進位制的Unicode//content:'\570B';//國//content:'\00A9';//©}結語​在瞭解了Unicode的使用和轉換後相信你已經可以解碼本篇文章中最一開始的那串內容是什麼了吧?{"name":"PJCHENder\u7db2\u9801\u524d\u7aef\u8cc7\u6e90\u7ad9"}試著用用看上面幾種不同的方法,像是console.log()或String.fromCodePoint()的方法來解碼Unicode吧!或者你也可以利用str.codePointAt()編碼打造一段屬於自己圈子內的低調碼,請有興趣的捧油們一起來解碼://自製低調碼[...'準備上車啦'].map((i)=>i.codePointAt().toString(16));//['6e96','5099','4e0a','8eca','5566']等等,那麼UTF-8,UTF-16,UTF-32是什麼?​透過Unicode(萬國碼)讓所有國家的文字符號都有個唯一的碼點可以在電腦內被辨認,但是這個碼點(從U+0000到U+10FFFF)要如何儲存在電腦中則不是Unicode要解決的,也就是說,要用什麼樣的方式才能有效的把所需的碼點存在電腦中,但又不佔據太多的容量則沒有在Unicode中被規範。

UTF-8,UTF-16或UTF-32則都可以視為是Unicode實做的一種方式,它們用不同的方式來規範要如何將Unicode中的碼點儲存在電腦中以被使用,如果直接把整個Unicode代碼搬進電腦裡儲存,可能會佔用太多不必要的空間(例如,UTF-32)。

在網際網路上最常被使用的則是UTF-8的編碼方式,而在JavaScript引擎中主要支援的則是UTF-16。

其他網際網路上常用編碼方式​除了用Unicode來為每個文字符號來進行編碼外,在網際網路上,也經常會使用HTMLEncode或者是URIEncode來將內容或網址進行編碼。

HTMLEncode​HTMLEncode的特點在於,它會用&開始;結束,例如+字串透過HTML轉換後會變成+,它也有可以用十六進位或十進位的方式表示:"+"=+=+=+HTMLEncodeCharacterReference:HTML編碼對照表。

URIEncode​在網際網路上最常被使用的則是UTF-8的編碼方式,它的特點是會用%開頭,許多的網址或文字內容為了確保正確性,常常會先使用URIEncode後再顯示。

文章最前面所提到的例子https://today.line.me/tw/pc/article/%E5%86%B0%E7%81%AB%E4%B9%8B%E5%9C%8B+%E5%86%B0%E5%B3%B6-ownNlj就是因為把這些中文字轉換成UTF-81編碼後的結果。

在JavaScript中提供encodeURI()和encodeURIComponent()的方法可以將字串轉換成UTF-8,這兩個函式的差別在於,encodeURI()不會對URI具有特殊意義的字符編碼(例如,ASCII碼、數字、-_.!~*'();/?:@&=+$,#),但encodeURIComponent()則是全部都會進行編碼,編碼完的內容會是UTF-8。

encodeURI('/');//'/'是URI中有意義的字符,不會進行編碼encodeURIComponent('/');//'%2F'encodeURI('&');//'&'是URI中有意義的字符,不會進行編碼encodeURIComponent('&');//'%26'encodeURIComponent('國');//'%E5%9C%8B'encodeURIComponent('💩');//'%F0%9F%92%A9'相對應的解碼方式則是decodeURI()和decodeURIComponent()。

decodeURI('https://today.line.me/tw/pc/article/%E5%86%B0%E7%81%AB%E4%B9%8B%E5%9C%8B+%E5%86%B0%E5%B3%B6-ownNlj',);//"https://today.line.me/tw/pc/article/冰火之國+冰島-ownNlj"延伸閱讀​推薦影片:計算機科學速成課(第四集):二進制,這段教學影片清楚說明了二進制的計算方式,並在後半段有提到文字符號的編碼概念。

若想要進一步瞭解Unicode如何轉換成UTF-8可以參考字符編碼筆記:ASCII,Unicode和UTF-8@阮一峰的網絡日誌。

若想要進一步瞭解Unicode,UTF-16和JavaScript間的關係,可以參考Unicode與JavaScript詳解@阮一峰的網絡日誌。

若想瞭解更多Unicode在JavaScript中的應用可以參考JavascriptUnicode@Andyyou大尺度私房菜若想要進一步瞭解ASCII和Unicode的關係,可參考What'sthedifferencebetweenasciiandunicode@StackOverflow參考工具​推薦工具:全字庫:方便查詢Unicode進位換算計算機ASCIITableUnicode查詢HTML字符對照表上一頁[web]記憶體問題memoryleak下一頁[gulp]learningresource什麼是字串編碼(StringEncode)?電腦只認得數字ASCII編碼(ASCIICode)Unicode(萬國碼)用來表示數值的不同方式:談談進位制不同進位制的表示使用JavaScript進行不同進位制間的轉換Unicode的表示方式(U+)碼點(CodePoint)基本名面和輔助平面JavaScript中提供的相關函式文字符號-->Unicode碼點(10進位)Unicode碼點-->文字符號在JavaScript字串中顯示Unicode字元只使用到Unicode基本平面時(\u)有使用到Unicode輔助平面時(\u{碼點})只使用到ASCII字符時(\x)統整一下在CSS中使用Unicode結語等等,那麼UTF-8,UTF-16,UTF-32是什麼?其他網際網路上常用編碼方式HTMLEncodeURIEncode延伸閱讀參考工具



請為這篇文章評分?