问题 如何在使用Unicode提交表单时避免使用浏览器Unicode规范化


在HTML中呈现以下Unicode文本时,事实证明浏览器(谷歌浏览器)可以采用某种形式 Unicode规范化 将数据发布回服务器时。 (可能在 表格C.)。

但是当使用圣经希伯来文(בְּרִיךְהוּא)文本时,这很容易打破文本,如 这里 (第9页)。

有没有办法避免浏览器自动文本规范化?

我写了一篇博文,更详细地描述了我所面临的问题: http://blog.hibernatingrhinos.com/12449/would-it-be-possible-to-have-a-web-browser-based-editor-for-an-hebrew-text


12270
2018-06-24 10:12


起源

@Hans没有。你为什么这么认为? - Fitzchak Yitzchaki
您不能简单地应用同一文档中描述的解决方法吗? - jalf
你问的是哪些特定的浏览器?据我所知,没有单一的标准化API可用于“在提交表单时禁用规范化”。各个浏览器可能有也可能没有控制它的选项。您是否想要一种方法让您的网站禁用规范化,或者让浏览器用户将浏览器配置为不规范化? - jalf
不,我没有任何算法来自动添加 CombiningGraphemeJoiner char,即使我有,我想完全避免标准化,以保持字符含义。 - Fitzchak Yitzchaki
是什么让您认为Google Chrome在发布表单数据时会对文本进行规范化?你能举个例子吗? - Jukka K. Korpela


答案:


这似乎是WebKit浏览器(Chrome,Safari)中的一个功能/错误;它们将表格数据标准化为NFC,这意味着,除了别的以外,将连续的组合标记重新排序为“规范”顺序。这对我来说是新的,在这种情况下也是坏消息。最糟糕的是,不同的浏览器表现不同。

使用测试用例的简化版本 http://blog.hibernatingrhinos.com/12449/would-it-be-possible-to-have-a-web-browser-based-editor-for-an-hebrew-text (使用只是回显原始数据的服务器端脚本),我注意到Chrome和Safari重新排序了U + 05E9 U + 05C1 U + 05B5(SHIN,SHIN DOT,TSERE)中的变音符号,而IE,Firefox和歌剧没有。

我还用拉丁字母e进行了简单的测试,接着是组合分音符U + 0308。 WebKit浏览器根据NFC规则将其转换为单个字符ë,而其他浏览器保持字符对完整。

自2006年以来,这似乎是一个故意的特征; https://bugs.webkit.org/show_bug.cgi?id=8769 自豪地宣布这是错误修复的一部分!这可以解释W3C政策文件的状态;它目前的版本在本期中是WebKit-minded,但其他浏览器供应商要么不感兴趣,要么故意反对“早期规范化”的想法。

我认为没有办法防止这种情况发生。但您可以警告用户不要使用Chrome和Safari。您甚至可以使用包含简单问题案例的隐藏字段,然后检查服务器端是否按原样传输,并告诉用户更改浏览器(如果不是)。

修复订单服务器端并不简单,因为常见的规范化例程显然不支持所需的订单。您可以标准化为完全分解的形式(NFD),然后使用您自己的代码重新排序组合标记。也许更简单,更安全,您可以运行一个临时替换例程,用其他序列替换组合标记的序列。这样会更安全,因为它不会影响你想要影响的字符以外的字符,而NFD会用变音符号等分解拉丁字母。

根据Unicode原则,规范等效的字符串(例如,仅按连续的变音符号的顺序不同)是相同数据的不同表示,但是与Unicode字符(代码点)的序列不同;他们不会在演讲中有所不同,但他们可能并且经常这样做。一般来说,你不应该 期望 程序将规范等效的字符串视为不同的程序 可能 做出改变。看到 Unicode规范化常见问题

常见问题解答条目声称圣经希伯来语的问题已经通过COMBINING GRAPHEME JOINER的引入得以解决。虽然它可以防止Chrome中的重新排序,但这是一种笨拙的方法,它可能会使渲染变得混乱(它在Web浏览器中会出现;变音符号可能会被错误地放错位置)。


10
2018-06-25 13:08



我认为这更像是一个错误,而不是一个功能,因为规范化不是在文本渲染上发生,而是在表单提交时发生。此时,规范化决策应该是服务器决策,而不是浏览器。 - Fitzchak Yitzchaki
我为此创建了一个问题, code.google.com/p/chromium/issues/... - Fitzchak Yitzchaki
+1:“但您可以警告用户不要使用Chrome和Safari。”通常会警告用户使用ie6-8。 - Timo Kähkönen
我是洛杉矶面临同样的问题(Bug?)。发表在这里 code.google.com/p/chromium/issues/detail?id=117128#。那么解决方案是什么?改变服务器端的字符?我也写了一个骚乱。 - Shiplu Mokaddim
在某些确定的规范化中将所有字符串存储在数据库中是不是更好?浏览器知道如何在给出它们的任何规范化中渲染/编辑UTF8。发送UTF-8(比如NFC)然后让他们编辑等,然后在存储上标准化为NFC。在规范化上进行设置允许搜索,而不是在返回用户键入的相同字节模式时进行搜索。这是你的选择。我们通常逐字存储,然后在搜索时使用特殊的非ascii旧学校搜索算法。 - Tom Andersen


可以通过发送Uint8Array而不是字符串来避免字符串规范化。首先,如上所述,将字符串的UTF-8数据作为Uint8Array 这里 通过@Moshev:

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;
}

然后你可以用普通的XHR或你最喜欢的Ajax库发布Uint8Array。如果您正在使用jQuery,请记住您需要指定 processData: false 防止jQuery尝试对其进行字符串化并撤消所有辛苦工作。


1
2017-09-16 18:17





您可以在提交之前操作客户端上的文本。如果插入Combining Grapheme Joiner,则可以通过JavaScript插入。

作为一个注意点,但这里是一个JSFiddle,逐个字母地获取字符(在Safari中测试,它不规范化文本): http://jsfiddle.net/TmtnA/


0
2017-09-05 10:46