日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

編碼歪傳在Windows上做開發(fā)的同學(xué),一定要選擇“使用UTF-8無BOM格式”保存

 看見就非常 2015-04-24

我保證這是最后一篇了,而且這次的內(nèi)容絕對都是很具體的,具體得連每篇博客開頭例行的摘要我都不知道該寫什么了!

典型亂碼

亂碼、問號、方塊

用文本編輯器打開一個文件,如果編碼不兼容,有時候會看到??????的東西,有時候會看到一團亂七八糟的文字,通常我們就統(tǒng)稱亂碼了。怎么用編碼的知識來理解呢?

前文中我們有說到實用的很多編碼方式都用的是變長字節(jié)編碼,很多字節(jié)都要結(jié)合它的上下文去解釋才是對的。例如:用UTF-8的算法去解析GBK的文件,就很容易發(fā)些這么些種情況:

  1. 一個字節(jié)序列并不是合法的UTF-8字符,比如以11111110開頭的字節(jié)序列。
  2. 一個字節(jié)序列碰巧符合UTF-8規(guī)則。

反過來看,用GBK的算法去解析UTF-8的文件其實也差不多,遇到第一種情況在顯示的時候可能就用問號代替,而遇到第二種情況就是出現(xiàn)一些風(fēng)馬牛不相及的雜亂文字。

方塊其實和問號本質(zhì)上一樣的,但方塊在現(xiàn)代瀏覽器里還有個很常見的情況,就是一個字符的編號在字體當(dāng)中并沒有定義,于是在排版和渲染的適合“智能”地用一個方塊來表示它了??吹椒綁K可以結(jié)合上下文,如果上下文當(dāng)中的非英字符顯示正確的,那么方塊可能是一些特殊符號,比如Emoji。

在寫服務(wù)端程序的時候要小心處理“半個字符”的問題,例如我們在前級對超長的數(shù)據(jù)進行截斷處理,剛好截斷掉一個變長編碼的字節(jié)序列,就會出現(xiàn)“半個字符”。一般半個字符都是鐵定會亂碼,一些容錯比較差的程序甚至?xí)?,比如一些做的不好的PHP的C擴展,嚴重的時候會出core。所以程序不懂編碼就別瞎截,甚至考慮到某些語言文字里的組合字符,就是知道編碼也別瞎截(真是細思恐極);

BOM

BOM就是Browser Object Model瀏覽器對象模型,不好意思拿錯劇本了。

BOM(Byte-Order Mark,字節(jié)序標(biāo)記)是Unicode碼點U+FEFF。它被定義來放在一個UTF-16文件的開頭,如果字節(jié)序列是FEFF那么這個文件就是大端序,如果字節(jié)序列是FFFE那么這個文件就是小端序。

UTF-8本身是沒有字節(jié)序的問題的(因為它是以單個字節(jié)為最小單位),但是Windows里面很多編輯器(比如記事本)會多此一舉的在UTF-8文件開頭加入EF BB FF也就是U+FEFF的UTF-8編碼。

如果你的PHP文件里面有一個這東西你就倒了大霉了,可能會:

  • 什么也看不見,可能是PHP引擎根本處理不了這個源代碼。
  • 頁面展現(xiàn)錯亂的情況,一般是因為在<doctype>之前輸出的非空格內(nèi)容造成了瀏覽器選擇錯誤的doctype。
  • 頁面上面有及格亂七八糟的字符,瀏覽器把它當(dāng)字符展示出來了。

于是建議在Windows上做開發(fā)的同學(xué),一定要選擇“使用UTF-8無BOM格式”保存,所以用記事本寫代碼裝X就不好使了,用Notepad++的可以注意選一下,它支持的文件編碼格式挺豐富的,用一些比較先進的跨平臺編輯器比如WebStorm、SublimeText它們都是沒BOM的。

錕斤拷

亂碼之所以叫亂碼,就是因為它是“亂”的。但是亂碼當(dāng)中最出名的就是“錕斤拷”,他出現(xiàn)次數(shù)太多了以至于看起來根本就沒那么“亂”。這就納了悶了,為什么全中國的網(wǎng)站亂碼里面都會有這個?

原因是,在將一些國家語言編碼體系,比如GB、BIG-5、EUC-JP等,轉(zhuǎn)換為Unicode的過程中,多少有一些字符是不在Unicode中的(比如一些偏旁部首在Unicode里是后來才收錄的),甚至它本身在原來的編碼體系里面就是非法字符的情況。

Unicode規(guī)定了U+FFFD當(dāng)作一個占位符用來表示這些字符,用UTF-8編碼它就是EF BF BD,連續(xù)多個這樣的字節(jié)序列出現(xiàn)就成了EF BF BD EF BF BD。如果是一個UTF-8的解析程序還好,而如果用一個GB的解析程序去打開,一個漢字2字節(jié),就成了“錕斤拷”。這里就是一個例子,用UTF-8編碼打開是問號,用GBK編碼打開的話就會看到錕斤拷,用hexdump或者UltraEdit這類任何16進制編輯器看的話就能看到里面都是EF BF BD。

要避免錕斤拷一個重要的點就是盡量減少程序當(dāng)中的編碼轉(zhuǎn)換。比如輸入是UTF-8,但是一個舊的模塊是GBK,把UTF-8轉(zhuǎn)成GBK交給舊的模塊處理,處理過程中舊模塊多多少少有些BUG的可能,再轉(zhuǎn)回來的時候就容易錕斤拷了。一個項目的源代碼在團隊里面被不同的人(他們編輯器配置不盡相同)開來開去,存來存去,也很容易出現(xiàn)錕斤拷。

燙燙燙、屯屯屯

這個和編碼轉(zhuǎn)換其實沒啥關(guān)系,在VC的DEBUG模式下,會把未初始化的棧內(nèi)存全部填成0xCC,未初始化的堆內(nèi)存填成0xCD,這樣做是讓你一眼就能看出來你開了內(nèi)存沒初始化。

而用GBK編碼的話,CC CC就是“燙”,CD CD就是“屯”。

URL Encode和Base64

URL Encode

URL Encode又稱為“百分號編碼”它主要用來在URI里面將特殊字符進行轉(zhuǎn)義,因為像/&、=等等這類字符在URI里面本身是有功能性的。

對于ASCII字符的編碼很簡單就是用%后跟ASCII編碼的16進制表示,例如/的ASCII char code是47,16進制表示是2F,于是它的URL Encode結(jié)果就是%2F

對于非ASCII字符,將它的每個字節(jié)進行相同規(guī)則的轉(zhuǎn)換,例如中文“編碼”的Unicode char code是U+7F16 7801,UTF-8編碼的字節(jié)序列是E7 BC 96 E7 A0 81,所以它按照UTF-8編碼的URL Encode結(jié)果就是%E7%BC%96%E7%A0%81

可以看出,URL Encode編碼非ASCII字符的時候,結(jié)果與使用的字符編碼有關(guān)。因此在頁面上提交表單、發(fā)起Ajax請求等操作的時候需要注意編碼。瀏覽器會按照當(dāng)前頁面所使用的字符編碼對表單體提交進行URL Encode,但使用JavaScript的encodeURIencodeURIComponent的時候則總是會使用UTF-8(參考MDN)。

表單提交的時候編碼是非常非常重要的,一旦錯了服務(wù)端解開數(shù)據(jù)的時候就會跪。比如Github在它們的搜索表單里面放了一個<input name="utf8" type="hidden" value="?">,其中那個對鉤?是U+2713,UTF-8編碼是E2 9C 93,他們可以在服務(wù)端檢測這個參數(shù)的值對不對從而對URL里用的編碼進行一個初步檢測。雖然我沒有看到他們使用其他編碼的情況,不過這樣也算是一個編碼協(xié)商和Check的手段吧。

在JavaScript中使用escape也可以達到URL Encode的效果,但是它對于非ASCII字符使用了一種非標(biāo)準(zhǔn)的的實現(xiàn),例如“編碼”會被escape%u7F16%u7801這種%uxxxx奇怪的表示,W3C把這個函數(shù)廢棄了,身為一名前端還用是打臉的哦。

Base64

Base64是一種用可見字符表示二進制數(shù)據(jù)的方法。它用了64個可見字符[A-Za-z0-9+/]。

Base64的編碼程序非常簡單,由于64=2^6,6和8的最小公倍數(shù)是24,也就是3byte,因此對輸入數(shù)據(jù)以3byte為一個單位,查表把它轉(zhuǎn)換成4個可見字符。

如果輸入末尾不足3byte,那就補足,補1個byte就在輸出末尾添加一個=,補2個byte同理。

Base64經(jīng)常用來在一些文本協(xié)議里面保存二進制數(shù)據(jù),比如HTTP協(xié)議,或者電子郵件的附件啊什么的。同時因為它的輸出對于人類而言不可讀,可以起到一些“混淆加密”的作用,事實上就有修改64個字符的排布來做一個變形Base64實現(xiàn)一個簡單加密算法的例子。從密碼學(xué)的角度看它基本上沒什么強度可言,但是足夠簡單,可以起到防君子不防小人的作用。

由于一個字符只能編碼6bit,自身卻占了8bit,8/6=1.33,因此使用Base64來表示數(shù)據(jù)的時候會浪費1/3的體積。對于在CSS里面用Base64的data-url方式表示圖片,用之前不妨簡單估算一下,膨脹的體積和一個HTTP請求頭比起來會相差多少,說不定漲太多了已經(jīng)損失掉省一個請求的收益了。

尾聲

終于整個系列都要結(jié)束了,理論的也好,實用的也好,基本上我覺得該說的都說了,要是以后再遇到亂碼,一定會很快知道問題所在。

最后還是要佩服并感謝一下ISO和Unicode聯(lián)盟,做了這么偉大的事情將全世界的語言文字統(tǒng)一收錄和編碼,而這當(dāng)中包括了那么多我們根本沒聽說過的奇怪的語言文字。正是因為他們的努力奠定了互聯(lián)網(wǎng)是一個無國界的世界,每天我們都能通過它獲得來自任何地方任何語言的信息。

哦,我上面說的不是某國的互聯(lián)網(wǎng)。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多