成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

細(xì)說Unicode(二) Unicode與JavaScript的糾葛

Achilles / 3708人閱讀

摘要:受到這個(gè)的影響,中的字符操作函數(shù)某些情況無法返回正確的結(jié)果。的碼點(diǎn),還有另外一種表示方法,稱為進(jìn)制轉(zhuǎn)義序列。這與我們的認(rèn)知有點(diǎn)不同,我們通常認(rèn)為一個(gè)表情符號也是一個(gè)字符,長度為。而如果通過來判斷字符串長度顯然是不夠準(zhǔn)確的。

大家對上一篇文章中提到的UCS編碼可能比較陌生。殊不知這就是JavaScript采用的編碼方法。

既然Unicode已經(jīng)統(tǒng)一了天下,為什么JavaScript不采用UTF的編碼方法呢?原因很簡單,因?yàn)镴avaScript誕生的時(shí)候UTF-8還尚未成熟,UTF-16更是到后面才出現(xiàn),而此時(shí)UCS已經(jīng)先行一步地完成了UCS-2。所以JavaScript采用了比UTF更早的UCS。也就是UCS-2。(記住只是編碼方法,實(shí)際上字符集還是Unicode字符集)

UCS-2 與 UTF-16

從命名上看,我們很容易猜出UCS-2占用2個(gè)字節(jié)。而UTF-16占用16位,也是2個(gè)字節(jié),那他們的編碼方式有什么不同呢?
對于2個(gè)字節(jié)的碼點(diǎn),UCS-2和UTF-16是沒有什么區(qū)別的。在基本平面上(2^16),UTF-16沿用了UCS-2的編碼,另外在輔助平面上,UTF-16還定義了4個(gè)字節(jié)的表示方法。簡單來說,UTF-16可看成是UCS-2的父集。在沒有輔助平面字符前,UTF-16與UCS-2所指的是同一的意思。但當(dāng)引入輔助平面字符后,就稱為UTF-16了。

由于JavaScript只能處理UCS-2編碼,造成所有字符都是2個(gè)字節(jié),如果是4個(gè)字節(jié)的字符,會被當(dāng)做兩個(gè)雙字節(jié)的字符處理。受到這個(gè)的影響,JavaScript中的字符操作函數(shù)某些情況無法返回正確的結(jié)果。

對于兩個(gè)字節(jié)的字符,js能夠根據(jù)碼點(diǎn)直接輸出對應(yīng)字符。例如小寫字母"a"的Unicode編碼就是U+0061。

U+0000 - U+00FF的碼點(diǎn),還有另外一種表示方法,稱為16進(jìn)制轉(zhuǎn)義序列。用"x"開頭,后面跟兩位的16進(jìn)制符。

大于兩個(gè)字符的碼點(diǎn),JavaScript就有點(diǎn)力不從心了。例如字符

這個(gè)符號的字符碼點(diǎn)為 "U+1F4A9", 控制臺的輸出結(jié)果是這樣的

這顯然不是正確的結(jié)果,那么這個(gè)符號是怎么產(chǎn)生的呢?

由于UCS-2每次只能讀取兩個(gè)字節(jié),所以 "U+1F4A9"被解讀為U+1F4A 和 9, 查閱Unicode映射表U+1F4A 對應(yīng)的是希臘語的擴(kuò)展,就是是符號0加一點(diǎn)。

剩下的9則被識別為普通的字符串符號"9"輸出了。

既然JavaScript無法處理大于兩個(gè)字節(jié)的符號,那對于互聯(lián)網(wǎng)上成千上萬的復(fù)雜字符和表情,豈不是束手無策?

非也!

我們在控制臺輸出這個(gè)碼點(diǎn):”uD83DuDCA9″

神奇的事情發(fā)生了,”uD83DuDCA9″竟然也能輸出符號。

如果我們多帶帶輸出這兩個(gè)碼點(diǎn),看會輸出什么字符:

兩個(gè)字符多帶帶輸出都是亂碼,Unicode無法識別對應(yīng)的字符。再次查閱映射表。

發(fā)現(xiàn)這兩個(gè)碼點(diǎn)分別落在了UTF-16的高半位和低半位。

原來UTF-16碰到第一個(gè)雙字節(jié)碼點(diǎn)在D800-DBFF之間時(shí),代碼不會直接讀取符號,而是將其存儲為高半?yún)^(qū),再往下讀取兩個(gè)字節(jié)的低半?yún)^(qū),合在一起再輸出符號。而這也是UCS-2的處理方式。

那么 "U+1F4A9"怎么轉(zhuǎn)化為高低位”uD83DuDCA9"呢,下面是轉(zhuǎn)換公式:

H = Math.floor((0x1F4A9-0x10000)/0x400)+0xD800 = 0xD83D

L = (0x1F4A9-0x10000) % 0x400+0xDC00 = 0xDCA9

既然我們已經(jīng)能夠在JavaScript中輸出輔助平面的字符了,那不是萬事大吉了嗎?

常見問題

考慮一個(gè)常用的前端場景——輸入框,通常會規(guī)定最大輸入字?jǐn)?shù)。嘗試輸出上面的符號長度, 發(fā)現(xiàn)長度是2。

這與我們的認(rèn)知有點(diǎn)不同,我們通常認(rèn)為一個(gè)表情符號也是一個(gè)字符,長度為1。而如果通過"xxx".length 來判斷字符串長度顯然是不夠準(zhǔn)確的。這個(gè)問題在ES6中能迎刃而解:

ES6中通過Array.from能準(zhǔn)確讀取字符長度

然而Array.from不是完美的,在某些場景下也無法滿足需求,況且還存在ES6的瀏覽器兼容性問題。

在ES5中,我們通過正則的判斷,也能得到Array.from的效果,而且擴(kuò)展性更高:

var regexAstralSymbols = /[uD800-uDBFF][uDC00-uDFFF]/g;

function countSymbols(string) {
    return string
        // 替換掉輔助平面的連字符
        .replace(regexAstralSymbols, "_")
        .length;
}

countSymbols("uD835uDC00"); //1

另外,JavaScript也提供了從碼點(diǎn)到字符的轉(zhuǎn)換函數(shù)。

//這里直接輸入進(jìn)制數(shù)0x0061或97,而不是字符串
String.fromCharCode(0x0061); //a
//輸出為10進(jìn)制數(shù)
"a".charCodeAt(0);//97 (16進(jìn)制0x0061)

而對于附加平面的符號,JavaScript又要跪了, 直接輸出低位 U+F4A9的字符,而該字符位于Unicode的私用區(qū),未定義,所以輸出"?"。

String.fromCharCode(0x1F4A9);//"?"

同樣的,我們將符號U+1F4A9變?yōu)楦叩匚惠斎?,就能成功輸?script type="text/javascript">showImg("https://segmentfault.com/img/remote/1460000007992415?w=39&h=17");符號

對于fromCharCode和charCodeAr這兩個(gè)方法,ES6 也提供了新的接口,對應(yīng)fromCodePoint和codePointAt,問題得到解決:

在處理字符串逆轉(zhuǎn),正則的匹配上,附加字符都會有問題,要處理這些問題,只有一條準(zhǔn)則,就是要對附加碼點(diǎn)做特殊處理。在ES6還沒全面支持的情況下,只能通過定義各種hack方法來解決。

關(guān)于Unicode跟JavaScript的糾葛就講到這,亂碼問題讓人費(fèi)解,但是只要了解了基本原理,問題往往就能迎刃而解。

參考文章:
https://zh.wikipedia.org/wiki
https://mathiasbynens.be/note...
http://www.ruanyifeng.com/blo...

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/86749.html

相關(guān)文章

  • 細(xì)說Unicode(一) Unicode初認(rèn)識

    摘要:所以中國人自己創(chuàng)造了一種字符編碼,每個(gè)漢字和符號用兩個(gè)字節(jié)來表示。第一個(gè)字節(jié)稱為高位字節(jié),第二個(gè)字節(jié)稱為低位字節(jié)。而目前為止我們使用最廣泛的中文編碼還是。 網(wǎng)站開發(fā)中經(jīng)常會被亂碼問題困擾。知道文件編碼錯(cuò)誤會導(dǎo)致亂碼,但對其中的原理卻知之甚少。偶然從某篇文章了解了Unicode,發(fā)現(xiàn)從這條線出發(fā)也牽引出了一系列缺失的知識點(diǎn)。通過研讀文章,基本了解了一些以前不明白的問題,所以整理了幾篇,從...

    loostudy 評論0 收藏0
  • 細(xì)說Unicode(三) Unicode 番外之附加字符

    摘要:在各種論壇上,經(jīng)常會看到一些奇怪的字符,它們的內(nèi)容會超出顯示范圍,舉個(gè)例子常見的還有一些有泰文字符組成的。第一種是對字符串文字區(qū)域設(shè)置最大高度,超出的部分自動隱藏。將附加字符進(jìn)行過濾,這種方法在某種程度上會誤殺一些需要正常顯示的附加符號。 在各種論壇上,經(jīng)常會看到一些奇怪的字符,它們的內(nèi)容會超出顯示范圍, 舉個(gè)例子: Z??????????????????A????????L?????...

    qujian 評論0 收藏0
  • 有關(guān)javascript強(qiáng)制轉(zhuǎn)換不得不說故事

    摘要:我們首先了解一下中有關(guān)類型轉(zhuǎn)換的知識。新增類型拋出異常從列表可以明顯看到少了一個(gè)類型轉(zhuǎn)換為的規(guī)則。這里要強(qiáng)調(diào)一點(diǎn)第二個(gè)表達(dá)式?jīng)]有涉及到強(qiáng)制類型轉(zhuǎn)換。如果文中有錯(cuò)誤或者有某些強(qiáng)制轉(zhuǎn)換的情形沒有涉及到請及時(shí)留言告知,我會修改并補(bǔ)充進(jìn)去。 javascript是一門非常奇特的語言,它有時(shí)候奇特的會讓人懷疑人生。比如讓我們看一下下面的一些奇葩例子: false == 0 ...

    xcold 評論0 收藏0
  • UnicodeJavaScript詳解

    摘要:本文大部分內(nèi)容轉(zhuǎn)自阮一峰前輩的文章,更新了部分內(nèi)容并加入了部分自己的理解。字符串處理函數(shù)新增了幾個(gè)專門處理字節(jié)碼點(diǎn)的函數(shù)。參考鏈接阮一峰與詳解輔助平面入門 本文大部分內(nèi)容轉(zhuǎn)自 阮一峰前輩的文章,更新了部分內(nèi)容并加入了部分自己的理解。 Unicode是什么? Unicode源于一個(gè)很簡單的想法:將全世界所有的字符包含在一個(gè)集合里,計(jì)算機(jī)只要支持這一個(gè)字符集,就能顯示所有的字符,再也不會有...

    econi 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<