15

在 HTML 中呈现以下 Unicode 文本时,事实证明,浏览器 (Google Chrome)在将数据发送回服务器时会执行某种形式的Unicode 规范化。(可能在表格 C中)。

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

有什么办法可以避免浏览器自动文本规范化?

我写了一篇博客文章,更详细地描述了我面临的问题:http: //blog.hibernatingrhinos.com/12449/would-it-be-possible-to-have-a-web-browser-based-希伯来文文本编辑器

4

3 回答 3

11

这似乎是 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 和 Opera不要。

我还用拉丁字母 e 进行了一个简单的测试,然后将分音符号 U+0308 组合在一起。WebKit 浏览器根据 NFC 规则将其转换为单个字符 ë,而其他浏览器则保持字符对不变。

自 2006 年以来,这似乎是一个有意的功能;https://bugs.webkit.org/show_bug.cgi?id=8769自豪地宣布这是错误修复的一部分!这或许可以解释 W3C 政策文件的现状;它的当前版本在这个问题上是基于 WebKit 的,但其他浏览器供应商要么不感兴趣,要么故意反对“早期规范化”的想法。</p>

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

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

根据 Unicode 原则,规范等效字符串(例如,仅在连续变音符号的顺序上有所不同)是相同数据的不同表示,但与 Unicode 字符序列(代码点)不同;预计它们的呈现方式不会有所不同,但它们可能并且经常会有所不同。通常,您不应期望程序将规范等效的字符串视为不同,尽管程序可能会有所不同。请参阅Unicode 规范化常见问题解答

常见问题解答条目声称圣经希伯来语的问题已通过引入组合字形连接器得到解决。尽管它可以防止在 Chrome 中重新排序,但这是一种笨拙的方法,并且可能会弄乱渲染(在 Web 浏览器中会出现这种情况;变音符号可能会严重错位)。

于 2012-06-25T13:08:51.827 回答
3

可以通过发送 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 尝试将其字符串化并撤消您所有的辛勤工作。

于 2015-09-16T18:17:15.610 回答
0

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

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

于 2012-09-05T10:46:46.813 回答