2012-06-24 34 views
11

在HTML中呈現以下Unicode文本時,事實證明,在將數據發回服務器時,瀏覽器(Google Chrome)執行某種形式的Unicode normalization。 (可能在Form C)。如何在使用Unicode提交表單時避免瀏覽器Unicode規範化

但是,當使用聖經希伯來文(בְּרִיךְהוּא)文本時,這可能很容易破壞文本,如here(第9頁)中所述。

有什麼辦法可以避免瀏覽器自動文字標準化?

我寫了一篇博客文章中更多的細節描述,我現在面臨這個問題: http://blog.hibernatingrhinos.com/12449/would-it-be-possible-to-have-a-web-browser-based-editor-for-an-hebrew-text

+0

@Hans no。你爲什麼這麼認爲? –

+0

難道你不能簡單地應用在同一文檔中描述的解決方法嗎? – jalf

+1

你在問什麼特定的瀏覽器?就我所知,「提交表單時禁用標準化」沒有單一的標準化API。單獨的瀏覽器可能有也可能沒有選項來控制它。你想讓你的網站禁用規範化,或者讓瀏覽器的用戶配置他的瀏覽器不正常嗎? – jalf

回答

10

這似乎是一個在WebKit瀏覽器(Chrome瀏覽器,Safari瀏覽器)功能/的bug;他們將表單數據規範化爲NFC,這意味着除其他外,將連續組合標記重新排序爲「規範」順序。這對我來說是新的,在這種情況下是個壞消息。最糟糕的是,不同的瀏覽器行爲有所不同。我發現Chrome和Safari對U + 05E9 U + 05C1 U + 05B5(SHIN)中的變音標記重新排序,SHIN DOT,TSERE),而IE,Firefox和Opera則沒有。

我還用拉丁文字母e進行了簡單測試,然後結合分音U + 0308進行測試。根據NFC規則,WebKit瀏覽器將其轉換爲單個字符ë,而其他瀏覽器則保持字符對不變。

從2006年開始,這似乎是一個有意圖的功能; https://bugs.webkit.org/show_bug.cgi?id=8769自豪地宣佈這是一個錯誤修復的一部分!這可以解釋W3C政策文件的狀態;其目前的版本是WebKit的頭腦在這個問題上,但其他瀏覽器供應商要麼沒有興趣或有意反對「早期正常化」的想法。

我不認爲有一種方法來防止這種情況。但是,您可以警告用戶不要使用Chrome和Safari。您甚至可以使用包含簡單問題案例的隱藏字段,然後檢查服務器端是否按原樣傳輸,並告訴用戶如果不是,則更改瀏覽器。

修復服務器端的順序並不簡單,因爲常見的規範化例程顯然不支持所需的順序。您可以將其歸一化爲完全分解形式(NFD),然後使用您自己的代碼重新排列組合標記。也許更簡單和更安全,你可以運行一個臨時替換程序,用其他序列替換組合標記序列。這會更安全,因爲它不會影響您想要影響的字符以外的字符,而NFD使用變音符分解拉丁字母等等。根據Unicode原則,規範等價的字符串(例如,僅在連續的變音符號的順序上不同)是相同數據的不同表示,但與Unicode字符(代碼點)的序列不同;他們預計不會有不同的表現,但他們可能並且經常這樣做。一般來說,您不應該將期望的程序視爲不同的經典等效字符串,但程序可能會有所不同。請參閱Unicode Normalization FAQ

FAQ條目聲稱聖經的希伯來語的問題已經通過引入結合圖解連接器來解決。儘管它阻止了Chrome中的重新排序,但這是一種笨拙的方法,並且可能會導致渲染混亂(它在Web瀏覽器中出現;變音標記可能會嚴重錯位)。

+0

我認爲這是一個比一個功能更多的錯誤,因爲規範化不是發生在文本呈現上,而是發生在表單提交上。此時,規範化決定應該是服務器之一,而不是瀏覽器。 –

+0

我爲此創建了一個問題,https://code.google.com/p/chromium/issues/detail?id=134623&thanks=134623&ts=1340703693 –

+0

+1:「但是您可以提醒用戶不要使用Chrome和Safari。」通常用戶會被警告使用ie6-8。 –

0

在提交之前,您可以在客戶端操縱文本。如果插入Combining Grapheme Joiner,你可以通過JavaScript插入。

作爲一個起始點,但這裏有一個的jsfiddle即獲得由字母字符字母(在Safari瀏覽器進行測試,並沒有標準化文本):http://jsfiddle.net/TmtnA/

1

有可能通過發送Uint8Array避免串正常化而不是一個字符串。首先,如@Moshev描述here讓您的字符串的UTF-8的數據作爲Uint8Array:

function utf8AbFromStr(str) { 
    var strUtf8 = unescape(encodeURIComponent(str)); 
    var ab = new Uint8Array(strUtf8.length); 
    for (var i = 0; i < strUtf8.length; i++) { 
     ab[i] = strUtf8.charCodeAt(i); 
    } 
    return ab; 
} 

然後你就可以張貼的Uint8Array與普通XHR或你最喜歡的Ajax庫。如果您使用的是jQuery,請記住,您需要指定processData: false以防止jQuery嘗試對其進行字符串化並撤消所有艱苦的工作。