2009-01-25 46 views
15

編碼問題是發展過程中已經咬傷了我次數最多的話題之一。每個平臺堅持自己的編碼,很可能有一些非UTF-8默認值在遊戲中。 (我通常在Linux上工作,默認爲UTF-8,我的同事大多在德語Windows上工作,默認爲ISO-8859-1或一些類似的Windows代碼頁)如何測試正確編碼的應用程序(如UTF-8)

我相信,UTF-8是合適的開發i18nable應用程序的標準。然而,根據我的經驗,編碼錯誤通常很晚才發現(儘管我位於德國,並且我們有一些特殊字符與ISO-8859-1一起提供了一些可檢測的差異)。

我相信,隨着一個完全非ASCII字符集(或那些知道使用此類字符集的語言)的開發者搶得提供測試數據開始。但是,對於我們其他人來說,必須有一種方法來緩解這種情況。

什麼[技術|工具|獎勵]在這裏的人使用?你如何讓你的合作開發者關注這些問題?你如何測試合規性?這些測試是手動還是自動進行的?

添加一個可能的答案前期:

我最近發現fliptitle.com(他們提供了一個簡單的方法來得到奇怪的字符寫入「uʍopǝpısdn」 *)和我打算用它們來提供容易覈查UTF-8字符串(如大多數字符所使用目前在一些奇怪的二進制編碼位置),但有一定必須是更系統的測試中,圖案或用於確保UTF-8兼容性/使用的技術。

注意:即使有一個公認的答案,我想知道更多的技術和模式,如果有一些。如果您有更多想法,請添加更多答案。要選擇一個答案來接受,這並不容易。我選擇了正確性最低的解決問題的正則表達式答案,但也有理由選擇其他答案。太糟糕了,只有一個答案可以接受。

謝謝您的輸入。

*)這是「倒掛」寫「倒掛」對於那些無法看到這些字符由於字體問題

+0

感謝(非常感謝)回答到現在 - 我想保持這個問題開了一段時間積累儘可能多的想法,解決這一問題成爲可能。 – 2009-01-25 21:42:30

回答

5

有一個regular expression to test if a string is valid UTF-8

$field =~ 
    m/\A(
    [\x09\x0A\x0D\x20-\x7E]   # ASCII 
    | [\xC2-\xDF][\x80-\xBF]    # non-overlong 2-byte 
    | \xE0[\xA0-\xBF][\x80-\xBF]  # excluding overlongs 
    | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte 
    | \xED[\x80-\x9F][\x80-\xBF]  # excluding surrogates 
    | \xF0[\x90-\xBF][\x80-\xBF]{2}  # planes 1-3 
    | [\xF1-\xF3][\x80-\xBF]{3}   # planes 4-15 
    | \xF4[\x80-\x8F][\x80-\xBF]{2}  # plane 16 
)*\z/x; 

但是這並不能保證文實際是UTF-8。

一個例子:字母ö(U + 00F6)和對應的UTF-8序列的字節序列是0xC3B6。
所以當你得到0xC3B6作爲輸入時,你可以說它是有效的UTF-8。但是你不能肯定地說信ö已經提交。
這是因爲想象不是使用UTF-8,而是使用ISO 8859-1。在那裏序列0xC3B6分別代表字符Ã(0xC3)和¶(0xB6)。
所以序列0xC3B6可以代表ö使用UTF-8或ö使用ISO 8859-1(儘管後者很不尋常)。

所以最終它只是猜測。

+0

哇 - 這是最不理想的角度解決問題。我印象深刻。此外,¶屬於最容易被檢測爲編碼錯誤的字符。 – 2009-01-25 21:33:09

2

本地化是非常艱難的。

我想你實際上是在問兩個問題。其中之一,你如何讓每個人都正確地工作在一個i8n應用程序上,不是技術性的,而是我認爲的項目管理問題。如果你希望人們使用一個通用的標準,比如UTF-8,那麼你只需要強制執行。工具將有所幫助,但人們首先需要被告知這樣做。

除此之外說,UTF-8是在我看來要走的路,這是很難給出一個答案,有關工具的問題。這真的取決於你正在做的項目的種類。例如,如果它是您正在討論的Java項目,那麼正確配置IDE以UTF-8編碼文件是一件簡單的事情。並確保您的UTF-8本地化位於外部資源文件中。

你當然可以做的一件事是做單元測試來檢查合規性。如果你的本地化的消息/標籤在資源文件中,那麼它很容易檢查我認爲它們是否正確的UTF-8編碼。

+0

你是對的 - 這是一次多個問題。主要是因爲我還沒有發現如何真正解決這個問題(除了「不犯錯誤」之外......)我正在尋找我的工具箱的任何工具來幫助當前和未來的項目。 – 2009-01-25 21:27:38

+1

加上 - 你的一個錯字描述了我經歷過的最好的情況:「它*很容易檢查......」我喜歡這個,它確實有一些事實;-) – 2009-01-25 21:30:00

3

帶字符編碼的真正麻煩的人經常會發現有多個編碼相關的錯誤,並且由於其他錯誤而引入了一些不正確的行爲。我沒有數過我見過這種事情的次數。

一如既往的目標是在每一個地方正確處理它。所以大多數時候簡單的單元測試都可以做到這一點,它甚至不需要非常複雜的字符集。我通過測試我們的民族特徵「ø」找到了所有的錯誤,因爲它在UTF-8和大多數其他字符集中的映射方式不同。

當所有的部分都正確完成時,聚合工作正常。我知道這聽起來微不足道,但是當談到字符集問題時,它總是適用於我;)

+0

這是我們公司的談話 - 「只要你做對了 - 問題就會消失」。 :)你如何確保UTF-8中的「ö」測試在ISO-8859-1中測試「說」 - 例如assertEquals(「ö」,「ö」)時不起作用成爲assertEquals(「Ã」,「Ã」) - 比喻 – 2009-01-25 21:39:15

+1

你用\ u轉義序列與非轉義字符斷言 – krosenvold 2009-01-26 04:40:58

1

在PHP中,我們使用mb_detect_encoding()和mb_convert_encoding()等mb_函數。他們並不完美,但他們讓我們在那裏的99.9%。比起我們有幾個正則表達式來去除時髦人物,這些人物有時會以某種方式出現。

如果你要國際化,你一定要使用UTF-8。我們還沒有找到將我們的所有數據轉換爲UTF-8的完美解決方案,但我不確定是否存在。你只需要不停地修補它。

11

謝謝fliptitle

我也試圖制定一個適當的測試計劃,以確保應用程序在整個系統中支持Unicode字符串。

我是雙語的,但是隻使用ISO-8859-1的兩種語言。因此,我一直在努力確定什麼是「真實生活」,「有意義」的方式來測試Unicode的各種可能性。

我只是碰到這種傳來:


後續帖子:

制定一些測試我的應用程序後,我意識到,我已經放在一起一個可能對其他人有用的編碼值的小列表。

我用我測試了以下國際字符串:

(注:這裏談到的一些UTF-8編碼的文本...希望你可以看到這在您的瀏覽器)

ユーザー別サイト
簡體中文
크로스플랫폼으로
מדוריםמבוקשים
أفضلالبحوث
Σὲγνωρίζωἀπὸ
ДесятуюМеждународную
แผ่นดินฮั่นเสื่อมโทรมแสนสังเวช
∮E⋅da= Q,N→∞,ΣF(1)=Π克(ⅰ)
的問題索緒爾étrangère
MANANA奧萊

(完的UTF-8外文/非英文文本)

但是,在測試過程中的不同點上,我意識到僅僅提供有關字符串在各自的外來字母中呈現時應該如何看待的信息是不夠的。我還需要知道正確的Unicode碼值數字,以及至少兩種編碼(UCS-2和UTF-8)中這些字符串的正確十六進制值。

下面是對應的代碼點編號和十六進制值:

str = L"\u30E6\u30FC\u30B6\u30FC\u5225\u30B5\u30A4\u30C8"; // JAPAN 
// Little endian UTF-16/UCS-2: e6 30 fc 30 b6 30 fc 30 25 52 b5 30 a4 30 c8 30 00 00 
// Hex of UTF-8: e3 83 a6 e3 83 bc e3 82 b6 e3 83 bc e5 88 a5 e3 82 b5 e3 82 a4 e3 83 88 00 

str = L"\u7B80\u4F53\u4E2D\u6587"; // CHINA 
// Little endian UTF-16/UCS-2: 80 7b 53 4f 2d 4e 87 65 00 00 
// Hex of UTF-8: e7 ae 80 e4 bd 93 e4 b8 ad e6 96 87 00 

str = L"\uD06C\uB85C\uC2A4 \uD50C\uB7AB\uD3FC\uC73C\uB85C"; // KOREA 
// Little endian UTF-16/UCS-2: 6c d0 5c b8 a4 c2 20 00 0c d5 ab b7 fc d3 3c c7 5c b8 00 00 
// Hex of UTF-8: ed 81 ac eb a1 9c ec 8a a4 20 ed 94 8c eb 9e ab ed 8f bc ec 9c bc eb a1 9c 00 

str = L"\u05DE\u05D3\u05D5\u05E8\u05D9\u05DD \u05DE\u05D1\u05D5\u05E7\u05E9\u05D9\u05DD"; // ISRAEL 
// Little endian UTF-16/UCS-2: de 05 d3 05 d5 05 e8 05 d9 05 dd 05 20 00 de 05 d1 05 d5 05 e7 05 e9 05 d9 05 dd 05 00 00 
// Hex of UTF-8: d7 9e d7 93 d7 95 d7 a8 d7 99 d7 9d 20 d7 9e d7 91 d7 95 d7 a7 d7 a9 d7 99 d7 9d 00 

str = L"\u0623\u0641\u0636\u0644 \u0627\u0644\u0628\u062D\u0648\u062B"; // EGYPT 
// Little endian UTF-16/UCS-2: 23 06 41 06 36 06 44 06 20 00 27 06 44 06 28 06 2d 06 48 06 2b 06 00 00 
// Hex of UTF-8: d8 a3 d9 81 d8 b6 d9 84 20 d8 a7 d9 84 d8 a8 d8 ad d9 88 d8 ab 00 

str = L"\u03A3\u1F72 \u03B3\u03BD\u03C9\u03C1\u03AF\u03B6\u03C9 \u1F00\u03C0\u1F78"; // GREECE 
// Little endian UTF-16/UCS-2: a3 03 72 1f 20 00 b3 03 bd 03 c9 03 c1 03 af 03 b6 03 c9 03 20 00 00 
// Hex of UTF-8: ce a3 e1 bd b2 20 ce b3 ce bd cf 89 cf 81 ce af ce b6 cf 89 20 e1 bc 80 cf 80 e1 bd b8 00 

str = L"\u0414\u0435\u0441\u044F\u0442\u0443\u044E \u041C\u0435\u0436\u0434\u0443\u043D\u0430\u0440\u043E\u0434\u043D\u0443\u044E"; // RUSSIA 
// Little endian UTF-16/UCS-2: 14 04 35 04 41 04 4f 04 42 04 43 04 4e 04 20 00 1c 04 35 04 36 04 34 04 43 04 3d 04 30 04 40 04 3e 04 34 04 3d 04 43 04 4e 04 00 00 
// Hex of UTF-8: d0 94 d0 b5 d1 81 d1 8f d1 82 d1 83 d1 8e 20 d0 9c d0 b5 d0 b6 d0 b4 d1 83 d0 bd d0 b0 d1 80 d0 be d0 b4 d0 bd d1 83 d1 8e 00 

str = L"\u0E41\u0E1C\u0E48\u0E19\u0E14\u0E34\u0E19\u0E2E\u0E31\u0E48\u0E19\u0E40\u0E2A\u0E37\u0E48\u0E2D\u0E21\u0E42\u0E17\u0E23\u0E21\u0E41\u0E2A\u0E19\u0E2A\u0E31\u0E07\u0E40\u0E27\u0E0A"; // THAILAND 
// Little endian UTF-16/UCS-2: 41 0e 1c 0e 48 0e 19 0e 14 0e 34 0e 19 0e 2e 0e 31 0e 48 0e 19 0e 40 0e 2a 0e 37 0e 48 0e 2d 0e 21 0e 42 0e 17 0e 23 0e 21 0e 41 0e 2a 0e 19 0e 2a 0e 31 0e 07 0e 40 0e 27 0e 0a 0e 00 00 
// Hex of UTF-8: e0 b9 81 e0 b8 9c e0 b9 88 e0 b8 99 e0 b8 94 e0 b8 b4 e0 b8 99 e0 b8 ae e0 b8 b1 e0 b9 88 e0 b8 99 e0 b9 80 e0 b8 aa e0 b8 b7 e0 b9 88 e0 b8 ad e0 b8 a1 e0 b9 82 e0 b8 97 e0 b8 a3 e0 b8 a1 e0 b9 81 e0 b8 aa e0 b8 99 e0 b8 aa e0 b8 b1 e0 b8 87 e0 b9 80 e0 b8 a7 e0 b8 8a 00 

str = L"\u222E E\u22C5da = Q, n \u2192 \u221E, \u2211 f(i) = \u220F g(i)"; // MATHEMATICS 
// Little endian UTF-16/UCS-2: 2e 22 20 00 45 00 c5 22 64 00 61 00 20 00 3d 00 20 00 51 00 2c 00 20 00 20 00 6e 00 20 00 92 21 20 00 1e 22 2c 00 20 00 11 22 20 00 66 00 28 00 69 00 29 00 20 00 3d 00 20 00 0f 22 20 00 67 00 28 00 69 00 29 00 00 00 
// Hex of UTF-8: e2 88 ae 20 45 e2 8b 85 64 61 20 3d 20 51 2c 20 20 6e 20 e2 86 92 20 e2 88 9e 2c 20 e2 88 91 20 66 28 69 29 20 3d 20 e2 88 8f 20 67 28 69 29 00 

str = L"fran\u00E7ais langue \u00E9trang\u00E8re"; // FRANCE 
// Little endian UTF-16/UCS-2: 66 00 72 00 61 00 6e 00 e7 00 61 00 69 00 73 00 20 00 6c 00 61 00 6e 00 67 00 75 00 65 00 20 00 e9 00 74 00 72 00 61 00 6e 00 67 00 e8 00 72 00 65 00 00 00 
// Hex of UTF-8: 66 72 61 6e c3 a7 61 69 73 20 6c 61 6e 67 75 65 20 c3 a9 74 72 61 6e 67 c3 a8 72 65 00 

str = L"ma\u00F1ana ol\u00E9"; // SPAIN 
// Little endian UTF-16/UCS-2: 6d 00 61 00 f1 00 61 00 6e 00 61 00 20 00 6f 00 6c 00 e9 00 00 00 
// Hex of UTF-8: 6d 61 c3 b1 61 6e 61 20 6f 6c c3 a9 00 

而且,這裏是顯示一些常見的「錯誤渲染」,可以在各種編輯器發生一對夫婦的圖像,即使底層字節是格式良好的UTF8。如果你看到任何這些渲染,這可能意味着你正確地產生了一個UTF8字符串,但是你的編輯器/瀏覽器試圖在UTF8以外的編碼下解釋它們。

Sample Renderings Num. 1

Sample Renderings Num. 2

相關問題