每个软件开发人员绝对必须了解 Unicode 和字符集的绝对最低限度(没有任何借口!
有沒(méi)有想過(guò)那個(gè)神秘的 Content-Type 標(biāo)簽?你知道,你應(yīng)該放在HTML中的那個(gè),你永遠(yuǎn)不知道它應(yīng)該是什么?
你有沒(méi)有收到過(guò)朋友發(fā)來(lái)的郵件,主題是“???? ?????? ??? ????”?
我沮喪地發(fā)現(xiàn),有多少軟件開(kāi)發(fā)人員并沒(méi)有真正完全了解字符集、編碼、Unicode 等神秘世界。幾年前,F(xiàn)ogBUGZ的Beta測(cè)試人員想知道它是否可以處理日語(yǔ)傳入的電子郵件。日語(yǔ)?他們有日語(yǔ)電子郵件嗎?我不知道。當(dāng)我仔細(xì)查看我們用于分析 MIME 電子郵件的商業(yè) ActiveX 控件時(shí),我們發(fā)現(xiàn)它對(duì)字符集做了完全錯(cuò)誤的事情,因此我們實(shí)際上必須編寫英雄代碼來(lái)撤消它所做的錯(cuò)誤轉(zhuǎn)換并正確地重做它。當(dāng)我查看另一個(gè)商業(yè)庫(kù)時(shí),它也有一個(gè)完全損壞的字符代碼實(shí)現(xiàn)。我與該軟件包的開(kāi)發(fā)人員通信,他有點(diǎn)認(rèn)為他們“對(duì)此無(wú)能為力”。像許多程序員一樣,他只是希望一切都能以某種方式結(jié)束。
但事實(shí)并非如此。當(dāng)我發(fā)現(xiàn)流行的 Web 開(kāi)發(fā)工具 PHP 幾乎完全無(wú)視字符編碼問(wèn)題時(shí),我輕率地使用 8 位字符,幾乎不可能開(kāi)發(fā)出好的國(guó)際 Web 應(yīng)用程序,我想,夠了。
所以我要宣布:如果你是 2003 年的一名程序員,你不知道字符、字符集、編碼和 Unicode 的基礎(chǔ)知識(shí),而我抓住了你,我會(huì)懲罰你,讓你在潛艇里剝洋蔥 6 個(gè)月。我發(fā)誓我會(huì)的。
還有一件事:
這并不難。
在這篇文章中,我將向你介紹每個(gè)在職程序員都應(yīng)該知道的內(nèi)容。所有關(guān)于“純文本 = ascii = 字符是 8 位”的東西不僅是錯(cuò)誤的,而且是無(wú)可救藥的錯(cuò)誤,如果你仍然以這種方式編程,你并不比不相信細(xì)菌的醫(yī)生好多少。在閱讀完本文之前,請(qǐng)不要再編寫一行代碼。
在我開(kāi)始之前,我應(yīng)該警告你,如果你是那些了解國(guó)際化的少數(shù)人之一,你會(huì)發(fā)現(xiàn)我的整個(gè)討論有點(diǎn)過(guò)于簡(jiǎn)單化了。我真的只是想在這里設(shè)定一個(gè)最低標(biāo)準(zhǔn),以便每個(gè)人都能理解正在發(fā)生的事情,并可以編寫代碼,希望能夠處理除英語(yǔ)子集以外的任何語(yǔ)言的文本,這些語(yǔ)言不包括帶重音的單詞。我應(yīng)該警告你,字符處理只是創(chuàng)建國(guó)際通用軟件所需的一小部分,但我一次只能寫一件事,所以今天是字符集。
歷史視角
理解這些東西的最簡(jiǎn)單方法是按時(shí)間順序排列。
你可能會(huì)認(rèn)為我要在這里談?wù)撓?EBCDIC 這樣的非常古老的字符集。好吧,我不會(huì)。EBCDIC與您的生活無(wú)關(guān)。我們不必回到那么久以前。
回到半古代,當(dāng)Unix被發(fā)明出來(lái),K&R正在編寫C編程語(yǔ)言時(shí),一切都非常簡(jiǎn)單。EBCDIC正在退出。唯一重要的字符是舊的無(wú)重音英文字母,我們有一個(gè)稱為 ASCII 的代碼,它能夠使用 32 到 127 之間的數(shù)字來(lái)表示每個(gè)字符。空格是 32,字母“A”是 65,等等。這可以方便地以 7 位存儲(chǔ)。當(dāng)時(shí)大多數(shù)計(jì)算機(jī)都使用 8 位字節(jié),所以你不僅可以存儲(chǔ)所有可能的 ASCII 字符,而且你有一整塊空余,如果你是邪惡的,你可以將其用于你自己的狡猾目的:WordStar 的昏暗燈泡實(shí)際上打開(kāi)了高位來(lái)指示單詞中的最后一個(gè)字母, 譴責(zé) WordStar 僅提供英文文本。低于 32 的代碼稱為不可打印,用于 cusing。開(kāi)玩笑。它們用于控制字符,例如 7 會(huì)使您的計(jì)算機(jī)發(fā)出嗶嗶聲,而 12 會(huì)導(dǎo)致當(dāng)前頁(yè)面的紙張從打印機(jī)中飛出并送入新頁(yè)面。
一切都很好,假設(shè)你是一個(gè)說(shuō)英語(yǔ)的人。
因?yàn)樽止?jié)最多有 128 位的空間,所以很多人開(kāi)始想,“天哪,我們可以將代碼 255-128 用于我們自己的目的。麻煩的是,很多人同時(shí)有這個(gè)想法,他們對(duì)從255到8088的空間應(yīng)該去哪里有自己的想法。IBM-PC 有一個(gè)后來(lái)被稱為 OEM 字符集的東西,它為歐洲語(yǔ)言提供了一些重音字符和一堆線條繪制字符......單杠、豎杠、右邊掛著小叮叮當(dāng)當(dāng)?shù)男「茆彽龋憧梢杂眠@些畫線字符在屏幕上制作漂亮的方框和線條,你仍然可以在干洗店的 128 電腦上看到它們運(yùn)行。事實(shí)上,一旦人們開(kāi)始在美國(guó)以外的地方購(gòu)買 PC,各種不同的 OEM 角色集就被想象出來(lái),它們都使用前 130 個(gè)角色來(lái)達(dá)到自己的目的。例如,在某些 PC 上,字符代碼 128 將顯示為 é,但在以色列銷售的計(jì)算機(jī)上,它是希伯來(lái)字母 Gimel (),因此當(dāng)美國(guó)人將他們的簡(jiǎn)歷發(fā)送到以色列時(shí),他們會(huì)以 rsums 的形式到達(dá)。在許多情況下,例如俄語(yǔ),對(duì)于如何處理上面的 <> 個(gè)字符有很多不同的想法,因此您甚至無(wú)法可靠地交換俄語(yǔ)文檔。
最終,這種 OEM 免費(fèi)產(chǎn)品被編入 ANSI 標(biāo)準(zhǔn)。在 ANSI 標(biāo)準(zhǔn)中,每個(gè)人都同意在 128 以下做什么,這與 ASCII 幾乎相同,但有很多不同的方法可以處理 128 及以上的字符,具體取決于您居住的地方。這些不同的系統(tǒng)稱為代碼頁(yè)。例如,在以色列,DOS 使用一個(gè)名為 862 的代碼頁(yè),而希臘用戶使用 737。它們?cè)?128 以下相同,但與 128 以上不同,所有有趣的字母都駐留在那里。MS-DOS的國(guó)家版本有幾十個(gè)這樣的代碼頁(yè),可以處理從英語(yǔ)到冰島語(yǔ)的所有內(nèi)容,他們甚至有一些“多語(yǔ)言”代碼頁(yè),可以在同一臺(tái)計(jì)算機(jī)上使用世界語(yǔ)和加利西亞語(yǔ)!哇!但是,除非您編寫自己的自定義程序來(lái)使用位圖圖形顯示所有內(nèi)容,否則在同一臺(tái)計(jì)算機(jī)上獲取希伯來(lái)語(yǔ)和希臘語(yǔ)是完全不可能的,因?yàn)橄2畞?lái)語(yǔ)和希臘語(yǔ)需要不同的代碼頁(yè),對(duì)高數(shù)字有不同的解釋。
與此同時(shí),在亞洲,更瘋狂的事情正在發(fā)生,因?yàn)閬喼拮帜副碛袛?shù)千個(gè)字母,而這些字母永遠(yuǎn)無(wú)法容納 8 位。這通常是通過(guò)稱為DBCS的混亂系統(tǒng)來(lái)解決的,DBCS是“雙字節(jié)字符集”,其中一些字母存儲(chǔ)在一個(gè)字節(jié)中,而其他字母則存儲(chǔ)在兩個(gè)字節(jié)中。在一根繩子中向前移動(dòng)很容易,但向后移動(dòng)幾乎是不可能的。鼓勵(lì)程序員不要使用 s++ 和 s– 來(lái)前后移動(dòng),而是調(diào)用 Windows 的 AnsiNext 和 AnsiPrev 等函數(shù),它們知道如何處理整個(gè)混亂。
但是,大多數(shù)人只是假裝一個(gè)字節(jié)是一個(gè)字符,一個(gè)字符是 8 位,只要你從不將字符串從一臺(tái)計(jì)算機(jī)移動(dòng)到另一臺(tái)計(jì)算機(jī),或者說(shuō)一種以上的語(yǔ)言,它就會(huì)一直有效。但是,當(dāng)然,一旦互聯(lián)網(wǎng)出現(xiàn),將字符串從一臺(tái)計(jì)算機(jī)移動(dòng)到另一臺(tái)計(jì)算機(jī)就變得司空見(jiàn)慣,整個(gè)混亂局面就崩潰了。幸運(yùn)的是,Unicode已經(jīng)被發(fā)明出來(lái)了。
統(tǒng)一碼
Unicode是一個(gè)勇敢的努力,它創(chuàng)造了一個(gè)單一的字符集,包括地球上所有合理的書寫系統(tǒng),以及一些虛構(gòu)的書寫系統(tǒng),如克林貢語(yǔ)。有些人誤以為 Unicode 只是一個(gè) 16 位代碼,其中每個(gè)字符需要 16 位,因此有 65,536 個(gè)可能的字符。實(shí)際上,這是不正確的。這是關(guān)于Unicode最常見(jiàn)的神話,所以如果你這么想,不要感到難過(guò)。
事實(shí)上,Unicode對(duì)字符的思考方式是不同的,你必須理解Unicode對(duì)事物的思考方式,否則什么都不會(huì)有意義。
到目前為止,我們假設(shè)一個(gè)字母映射到一些可以存儲(chǔ)在磁盤或內(nèi)存中的位:
A -> 0100 0001
在Unicode中,一個(gè)字母映射到一個(gè)叫做碼位的東西,這仍然只是一個(gè)理論概念。該代碼點(diǎn)如何在內(nèi)存或磁盤上表示是一個(gè)完整的故事。
在Unicode中,字母A是柏拉圖式的理想。它只是漂浮在天堂:
一個(gè)
這個(gè)柏拉圖式的 A 與 B 不同,與 a 不同,但與 A 和 A 和 A 相同。Times New Roman 字體中的 A 與 Helvetica 字體中的 A 是相同的字符,但與小寫的“a”不同,這種想法似乎沒(méi)有太大爭(zhēng)議,但在某些語(yǔ)言中,僅僅弄清楚字母是什么就會(huì)引起爭(zhēng)議。德語(yǔ)字母 ? 是真正的字母還是只是一種花哨的 ss 書寫方式?如果一個(gè)字母的形狀在單詞末尾發(fā)生了變化,那是一個(gè)不同的字母嗎?希伯來(lái)語(yǔ)說(shuō)“是”,阿拉伯語(yǔ)說(shuō)“不是”。無(wú)論如何,Unicode聯(lián)盟的聰明人在過(guò)去十年左右的時(shí)間里一直在弄清楚這一點(diǎn),伴隨著大量高度政治化的辯論,你不必?fù)?dān)心。他們已經(jīng)想通了。
每個(gè)字母表中的每個(gè)柏拉圖字母都由Unicode聯(lián)盟分配一個(gè)幻數(shù),其寫法如下:U+0639。這個(gè)幻數(shù)稱為碼位。U+ 表示“Unicode”,數(shù)字是十六進(jìn)制的。U+0639 是阿拉伯字母 Ain。英文字母 A 是 U+0041。您可以使用 Windows 2000/XP 上的 charmap 實(shí)用程序或訪問(wèn) Unicode 網(wǎng)站找到它們。
Unicode 可以定義的字母數(shù)量沒(méi)有真正的限制,事實(shí)上它們已經(jīng)超過(guò)了 65,536 個(gè),因此并非每個(gè) Unicode 字母都可以真正壓縮成兩個(gè)字節(jié),但這無(wú)論如何都是一個(gè)神話。
好的,假設(shè)我們有一個(gè)字符串:
你好
在 Unicode 中,它對(duì)應(yīng)于以下五個(gè)代碼點(diǎn):
U+0048 U+0065 U+006C U+006C U+006F。
只是一堆代碼點(diǎn)。數(shù)字,真的。我們還沒(méi)有說(shuō)任何關(guān)于如何將其存儲(chǔ)在內(nèi)存中或在電子郵件中表示它的任何內(nèi)容。
編碼
這就是編碼的用武之地。
Unicode編碼的最早想法,導(dǎo)致了關(guān)于兩個(gè)字節(jié)的神話,是,嘿,讓我們把這些數(shù)字分別存儲(chǔ)在兩個(gè)字節(jié)中。所以你好變成了
00 48 00 65 00 6C 00 6C 00 6F
右?沒(méi)那么快!難道不能也是:
48 00 65 00 6C 00 6C 00 6F 00 ?
嗯,從技術(shù)上講,是的,我確實(shí)相信它可以,事實(shí)上,早期的實(shí)現(xiàn)者希望能夠以高端或低端模式存儲(chǔ)他們的 Unicode 碼位,無(wú)論他們的特定 CPU 在哪個(gè)模式下最快,瞧,現(xiàn)在是晚上和早上,已經(jīng)有兩種方法來(lái)存儲(chǔ) Unicode。因此,人們被迫想出一個(gè)奇怪的約定,即在每個(gè)Unicode字符串的開(kāi)頭存儲(chǔ)一個(gè)FE FF;這稱為 Unicode 字節(jié)順序標(biāo)記,如果您要交換高字節(jié)和低字節(jié),它看起來(lái)像 FF FE,讀取字符串的人會(huì)知道他們必須每隔一個(gè)字節(jié)交換一次。唷。并非每個(gè) Unicode 字符串的開(kāi)頭都有一個(gè)字節(jié)順序標(biāo)記。
有一段時(shí)間,這似乎已經(jīng)足夠好了,但程序員們卻在抱怨。“看看那些零!”他們說(shuō),因?yàn)樗麄兪敲绹?guó)人,他們看到的是英文文本,很少使用U+00FF以上的代碼點(diǎn)。他們也是加利福尼亞的自由派嬉皮士,他們想要保護(hù)(冷笑)。如果他們是德克薩斯人,他們不會(huì)介意消耗兩倍的字節(jié)數(shù)。但是那些加利福尼亞的懦夫無(wú)法忍受將字符串所需的存儲(chǔ)量增加一倍的想法,無(wú)論如何,已經(jīng)有所有這些使用各種 ANSI 和 DBCS 字符集的狗狗文檔,誰(shuí)來(lái)轉(zhuǎn)換它們?莫伊?僅出于這個(gè)原因,大多數(shù)人決定忽略Unicode好幾年,與此同時(shí),情況變得更糟。
因此發(fā)明了 UTF-8 的絕妙概念。UTF-8 是另一個(gè)系統(tǒng),用于使用 8 位字節(jié)將 Unicode 碼位字符串(即那些神奇的 U+ 數(shù)字)存儲(chǔ)在內(nèi)存中。在 UTF-8 中,從 0 到 127 的每個(gè)碼位都存儲(chǔ)在一個(gè)字節(jié)中。只有 128 及以上的代碼點(diǎn)使用 2、3 存儲(chǔ),實(shí)際上最多存儲(chǔ) 6 個(gè)字節(jié)。
這有一個(gè)巧妙的副作用,即英語(yǔ)文本在 UTF-8 中看起來(lái)與在 ASCII 中完全相同,因此美國(guó)人甚至不會(huì)注意到任何錯(cuò)誤。只有世界其他地方必須跳過(guò)鐵環(huán)。具體來(lái)說(shuō),U+0048 U+0065 U+006C U+006C U+006F 的 Hello 將存儲(chǔ)為 48 65 6C 6C 6F,看哪!與存儲(chǔ)在 ASCII 和 ANSI 以及地球上的每個(gè) OEM 字符集中的相同。現(xiàn)在,如果你膽大妄為地使用重音字母、希臘字母或克林貢字母,你將不得不使用幾個(gè)字節(jié)來(lái)存儲(chǔ)一個(gè)碼位,但美國(guó)人永遠(yuǎn)不會(huì)注意到。(UTF-8 還具有一個(gè)很好的屬性,即想要使用單個(gè) 0 字節(jié)作為 null 終止符的無(wú)知舊字符串處理代碼不會(huì)截?cái)嘧址?/p>
到目前為止,我已經(jīng)告訴了您三種編碼Unicode的方法。傳統(tǒng)的 save-it-in-two-byte 方法稱為 UCS-2(因?yàn)樗袃蓚€(gè)字節(jié))或 UTF-16(因?yàn)樗?16 位),您仍然需要弄清楚它是高端 UCS-2 還是低端 UCS-2。還有流行的新 UTF-8 標(biāo)準(zhǔn),它有一個(gè)很好的特性,如果你有幸巧合地使用英語(yǔ)文本和腦死亡程序,而這些程序完全不知道除了 ASCII 之外還有任何東西,它也可以很好地工作。
實(shí)際上還有很多其他的Unicode編碼方法。有一種叫做 UTF-7 的東西,它很像 UTF-8,但保證高位永遠(yuǎn)為零,所以如果你必須通過(guò)某種嚴(yán)厲的警察國(guó)家電子郵件系統(tǒng)傳遞 Unicode,認(rèn)為 7 位就足夠了,謝謝你,它仍然可以毫發(fā)無(wú)損地?cái)D過(guò)去。有 UCS-4,它以 4 個(gè)字節(jié)的形式存儲(chǔ)每個(gè)碼位,它有一個(gè)很好的特性,即每個(gè)碼位都可以存儲(chǔ)在相同數(shù)量的字節(jié)中,但是,天哪,即使是德克薩斯人也不會(huì)如此大膽地浪費(fèi)那么多內(nèi)存。
事實(shí)上,現(xiàn)在你正在考慮由Unicode碼位表示的柏拉圖式理想字母,這些Unicode碼位也可以用任何老式的編碼方案進(jìn)行編碼!例如,您可以用 ASCII 編碼 Hello 的 Unicode 字符串 (U+0048 U+0065 U+006C U+006C U+006F),或者舊的 OEM 希臘語(yǔ)編碼,或希伯來(lái)語(yǔ) ANSI 編碼,或者迄今為止發(fā)明的數(shù)百種編碼中的任何一種,但有一個(gè)問(wèn)題:某些字母可能不會(huì)顯示!如果嘗試在嘗試表示它的編碼中沒(méi)有等效的 Unicode 碼位,通常會(huì)得到一個(gè)小問(wèn)號(hào):?或者,如果你真的很好,一個(gè)盒子。你得到了哪個(gè)?-> ?
有數(shù)百種傳統(tǒng)編碼只能正確存儲(chǔ)一些碼位,并將所有其他碼位更改為問(wèn)號(hào)。一些流行的英語(yǔ)文本編碼是 Windows-1252(西歐語(yǔ)言的 Windows 9x 標(biāo)準(zhǔn))和 ISO-8859-1,又名拉丁語(yǔ) 1(也適用于任何西歐語(yǔ)言)。但是嘗試將俄語(yǔ)或希伯來(lái)語(yǔ)字母存儲(chǔ)在這些編碼中,你會(huì)得到一堆問(wèn)號(hào)。UTF 7、8、16 和 32 都具有能夠正確存儲(chǔ)任何代碼點(diǎn)的良好屬性。
關(guān)于編碼的最重要的一個(gè)事實(shí)
如果你完全忘記了我剛才解釋的一切,請(qǐng)記住一個(gè)極其重要的事實(shí)。在不知道字符串使用什么編碼的情況下?lián)碛凶址菦](méi)有意義的。您不能再把頭埋在沙子里,假裝“純”文本是 ASCII。
沒(méi)有純文本這樣的東西。
如果在內(nèi)存中、文件或電子郵件中有一個(gè)字符串,則必須知道它采用的編碼,否則無(wú)法正確解釋它或向用戶顯示它。
幾乎每一個(gè)愚蠢的“我的網(wǎng)站看起來(lái)像胡言亂語(yǔ)”或“當(dāng)我使用口音時(shí)她無(wú)法閱讀我的電子郵件”的問(wèn)題都?xì)w結(jié)為一個(gè)天真的程序員,他不明白一個(gè)簡(jiǎn)單的事實(shí),即如果你不告訴我特定字符串是使用 UTF-8 還是 ASCII 或 ISO 8859-1(拉丁語(yǔ) 1)或 Windows 1252(西歐)編碼的, 您根本無(wú)法正確顯示它,甚至無(wú)法弄清楚它的結(jié)束位置。有超過(guò)一百種編碼,在代碼點(diǎn) 127 以上,所有賭注都已關(guān)閉。
我們?nèi)绾伪A粲嘘P(guān)字符串使用的編碼的信息?嗯,有標(biāo)準(zhǔn)的方法可以做到這一點(diǎn)。對(duì)于電子郵件,表單的標(biāo)題中應(yīng)包含一個(gè)字符串
內(nèi)容類型:text/plain;字符集=“UTF-8”
對(duì)于網(wǎng)頁(yè),最初的想法是 Web 服務(wù)器將返回一個(gè)類似的 Content-Type http 標(biāo)頭以及網(wǎng)頁(yè)本身——不是在 HTML 本身中,而是作為在 HTML 頁(yè)面之前發(fā)送的響應(yīng)標(biāo)頭之一。
這會(huì)導(dǎo)致問(wèn)題。假設(shè)您有一個(gè)大型 Web 服務(wù)器,其中包含許多站點(diǎn)和數(shù)百個(gè)頁(yè)面,這些頁(yè)面由許多人以多種不同的語(yǔ)言貢獻(xiàn),并且所有頁(yè)面都使用他們的 Microsoft FrontPage 副本認(rèn)為適合生成的任何編碼。Web 服務(wù)器本身并不知道每個(gè)文件是用什么編碼編寫的,因此它無(wú)法發(fā)送 Content-Type 標(biāo)頭。
如果您可以使用某種特殊標(biāo)簽將 HTML 文件的 Content-Type 直接放在 HTML 文件本身中,那就太方便了。當(dāng)然,這讓純粹主義者發(fā)瘋了......你怎么能讀HTML文件,直到你知道它是什么編碼?!幸運(yùn)的是,幾乎所有常用的編碼都對(duì) 32 到 127 之間的字符執(zhí)行相同的操作,因此您始終可以在 HTML 頁(yè)面上走到這一步,而無(wú)需開(kāi)始使用有趣的字母:
<html>
<head>
<meta http-equiv=“內(nèi)容類型” content=“text/html;字符集=UTF-8“>
但是這個(gè)元標(biāo)記實(shí)際上必須是<head>部分的第一件事,因?yàn)橐坏?Web 瀏覽器看到這個(gè)標(biāo)簽,它就會(huì)停止解析頁(yè)面,并在使用您指定的編碼重新解釋整個(gè)頁(yè)面后重新開(kāi)始。
如果 Web 瀏覽器在 http 標(biāo)頭或 meta 標(biāo)記中找不到任何 Content-Type,它們會(huì)怎么做?Internet Explorer 實(shí)際上做了一些非常有趣的事情:它試圖根據(jù)各種語(yǔ)言的典型編碼中各種字節(jié)在典型文本中出現(xiàn)的頻率來(lái)猜測(cè)使用了哪種語(yǔ)言和編碼。因?yàn)楦鞣N舊的 8 位代碼頁(yè)傾向于將其國(guó)家字母放在 128 到 255 之間的不同范圍內(nèi),并且因?yàn)槊糠N人類語(yǔ)言都有不同的字母使用特征直方圖,這實(shí)際上有機(jī)會(huì)奏效。這確實(shí)很奇怪,但它似乎確實(shí)經(jīng)常起作用,以至于天真的網(wǎng)頁(yè)作者從來(lái)不知道他們需要 Content-Type 標(biāo)頭,在 Web 瀏覽器中查看他們的頁(yè)面,它看起來(lái)還不錯(cuò),直到有一天,他們寫的東西不完全符合他們母語(yǔ)的字母頻率分布,而 Internet Explorer 確定它是韓語(yǔ)并這樣顯示它, 我認(rèn)為,證明波斯特爾定律關(guān)于“在你發(fā)出的東西上保守,在你接受的東西上自由”的觀點(diǎn),坦率地說(shuō),這不是一個(gè)好的工程原則。無(wú)論如何,這個(gè)網(wǎng)站是用保加利亞語(yǔ)寫的,但似乎是韓國(guó)人(甚至沒(méi)有凝聚力的韓國(guó)人),可憐的讀者在做什么?他使用 View |編碼菜單并嘗試一堆不同的編碼(東歐語(yǔ)言至少有十幾種),直到圖片更清晰。如果他知道這樣做,大多數(shù)人都不知道。
對(duì)于我公司發(fā)布的最新版本的 CityDesk(網(wǎng)站管理軟件),我們決定在內(nèi)部使用 UCS-2(雙字節(jié))Unicode 進(jìn)行所有操作,這是 Visual Basic、COM 和 Windows NT/2000/XP 用作其本機(jī)字符串類型。C++代碼中,我們只是將字符串聲明為 wchar_t(“寬字符”)而不是 char,并使用 wcs 函數(shù)而不是 str 函數(shù)(例如,wcscat 和 wcslen 而不是 strcat 和 strlen)。 要在 C 代碼中創(chuàng)建文字 UCS-2 字符串,只需在它前面加上一個(gè) L,如下所示:L“Hello”。
當(dāng) CityDesk 發(fā)布網(wǎng)頁(yè)時(shí),它會(huì)將其轉(zhuǎn)換為 UTF-8 編碼,該編碼多年來(lái)一直受到 Web 瀏覽器的良好支持。這就是 Joel on Software 的所有 29 種語(yǔ)言版本的編碼方式,我還沒(méi)有聽(tīng)說(shuō)過(guò)一個(gè)人在查看它們時(shí)遇到任何問(wèn)題。
這篇文章越來(lái)越長(zhǎng),我不可能涵蓋所有關(guān)于字符編碼和 Unicode 的知識(shí),但我希望如果你已經(jīng)讀到這里,你有足夠的知識(shí)回到編程,使用抗生素而不是水蛭和咒語(yǔ),我現(xiàn)在將交給你。