Как избежать браузеров Нормализация Юникода при отправке формы с помощью Unicode

При визуализации следующего текста в формате Unicode в HTML получается, что браузер (Google Chrome) выполняет некоторую форму Unicode normalization при публикации данные обратно на сервер. (Возможно, в Форма C).

Но при использовании библейского текста на иврите (ב ְּ רִיך ְ הוּא) это может легко сломать текст, как описано в здесь (стр. 9).

Есть ли способ избежать автоматической коррекции текста браузером?

Я написал сообщение в блоге, в котором более подробно описывается проблема, с которой я столкнулся: http://blog.hibernatingrhinos.com/12449/would-it-be-possible-to-have-a-web-browser-based-editor-for-an-hebrew-text

Ответ 1

Это, по-видимому, является признаком/ошибкой в ​​браузерах WebKit (Chrome, Safari); они нормализуют данные формы в NFC, что означает, среди прочего, переупорядочивание последовательных комбинационных меток в "канонический" порядок. Это было ново для меня и плохие новости в подобных случаях. Хуже всего то, что разные браузеры ведут себя по-другому.

Используя упрощенную версию вашего тестового примера http://blog.hibernatingrhinos.com/12449/would-it-be-possible-to-have-a-web-browser-based-editor-for-an-hebrew-text (используя серверную часть script, которая просто перекликается с необработанными данными), я заметил, что Chrome и Safari переупорядочивает диакритические знаки в U + 05E9 U + 05C1 U + 05B5 (SHIN, SHIN DOT, TSERE), тогда как IE, Firefox и Opera этого не делают.

Я также провел простой тест с латинской буквой e, а затем комбинировал diaeresis U + 0308. Браузеры WebKit преобразуют его в одиночный символ ë, в соответствии с правилами NFC, тогда как другие браузеры сохраняют пару символов неповрежденными.

Это кажется умышленной особенностью, начиная с 2006 года; https://bugs.webkit.org/show_bug.cgi?id=8769 с гордостью объявляет об этом как об ошибке! Это может объяснить статус документа политики W3C; его текущая версия WebKit-minded в этом выпуске, но другие производители браузеров либо заинтересованы, либо сознательно выступают против идеи "ранней нормализации".

Я не думаю, что есть способ предотвратить это. Но вы можете предупредить пользователей об использовании Chrome и Safari. Вы даже можете использовать скрытое поле, содержащее простой случай проблемы, а затем проверить серверную сторону, было ли оно передано как есть, и сообщить пользователю об изменении браузера, если это не так.

Фиксирование серверной части заказа не является простым, поскольку обычные процедуры нормализации, по-видимому, не поддерживают требуемый порядок. Вы можете нормализовать полностью разложенную форму (NFD), а затем переупорядочить комбинации меток, используя свой собственный код для этой цели. Возможно, проще и безопаснее, вы можете просто запустить специальную подпрограмму замены, которая заменяет последовательности совмещения меток с другими последовательностями. Это было бы безопаснее, потому что это не повлияло бы на персонажей, кроме тех, которые вы хотите повлиять, в то время как NFD разлагает латинские буквы с диакритикой, между прочим.

В соответствии с принципами Unicode канонически эквивалентные строки (например, отличающиеся только порядком последовательных диакритических знаков) представляют собой разные представления одних и тех же данных, но различаются как последовательности символов Unicode (кодовые точки); они не должны отличаться в представлении, но они могут и часто это делают. Как правило, вы не должны ожидать, что программы будут обрабатывать канонически эквивалентные строки как разные, хотя программы могут иметь значение. См. Часто задаваемые вопросы о нормализации Unicode.

В разделе часто задаваемых вопросов утверждается, что проблемы библейского иврита были решены путем внедрения КОМБИНИРОВАННОГО СОГЛАШЕНИЯ ГРАФЕМЫ. Хотя он предотвращает переупорядочение в Chrome, его неуклюжий метод, и он может испортить рендеринг (он работает в веб-браузерах, диакритические знаки могут сильно ухудшиться).

Ответ 2

Можно избежать нормализации строки, отправив Uint8Array, а не строку. Во-первых, получите данные UTF-8 вашей строки в виде Uint8Array, как описано здесь by @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;
}

Затем вы можете отправить этот Uint8Array с помощью простой XHR или вашей любимой библиотеки Ajax. Если вы используете jQuery, имейте в виду, что вам нужно указать processData: false, чтобы предотвратить попытку jQuery скрепить его и отменить всю вашу тяжелую работу.

Ответ 3

Вы можете манипулировать текстом на стороне клиента перед отправкой. Если вставка Combining Grapheme Joiner работает, вы можете вставить его через JavaScript.

В качестве точки зрения, но здесь JSFiddle, который получает буквы буквой (проверяется в Safari и не нормализует текст): http://jsfiddle.net/TmtnA/