Flash CS4/AS3: различное поведение между консолью и текстовой областью для печати символов UTF-16

trace(escape("д"));

напечатает "%D0%B4", правильную кодировку URL для этого символа (кириллический эквивалент "A").

Однако, если бы я сделал..

myTextArea.htmlText += unescape("%D0%B4");

Что печатается:

д

что конечно неправильно. Однако простое отслеживание приведенного выше unescape возвращает правильный символ кириллицы! Для этой техасской области экранирование "д" возвращает кодовую точку Юникода "%u0434".

Я не уверен, что именно происходит, чтобы все испортить, но...

UTF-16 д в веб-кодировке: %FE%FF%00%D0%00%B4

В то время как

UTF-16 ä в веб-кодировке: %00%D0%00%B4

Таким образом, это значение дополняется чем-то в начале. Почему трассировка предоставляет другой текст, чем печать в (пустую) текстовую область? Что происходит?

Рассматриваемая текстовая область не имеет никаких странных свойств кодирования, связанных с ней, если такие вещи вообще возможны.


person Amalgovinus    schedule 31.03.2011    source источник


Ответы (1)


Проблема в unescape (escape тоже может быть проблемой, но в данном случае она не виновата). Эти функции не поддерживают многобайтность. Что делает escape, так это: он берет байт во входной строке и возвращает его шестнадцатеричное представление с добавленным %. unescape делает наоборот. Ключевым моментом здесь является то, что они работают с байтами, а не с символами.

Вам нужно encodeURIComponent / decodeURIComponent. Оба используют utf-8 в качестве схемы кодирования строк (кодировка, используемая flash везде). Обратите внимание, что это не utf-16 (на что вам не следует обращать внимание, если речь идет о флэш-памяти).

encodeURIComponent("д"); //%D0%B4
decodeURIComponent("%D0%B4"); // д

Теперь, если вы хотите копнуть немного глубже, вот что происходит (это предполагает базовые знания о том, как работает utf-8).

escape("д")

Это возвращает

%D0%B4

Почему?

«д» интерпретируется flash как utf-8. Код этого символа — 0x0434.

В двоичном формате:

0000 0100 0011 0100

Он помещается в два байта utf-8, поэтому кодируется следующим образом (где e означает бит кодирования, а p означает бит полезной нагрузки):

1101 0000 1011 0100
eeep pppp eepp pppp 

Преобразовав его в шестнадцатеричный, получим:

0xd0  0xb4

Итак, 0xd0,0xb4 — это кодировка utf-8 «д».

Это подается на escape. escape видит два байта и дает вам:

%d0%b4

Теперь вы передаете это unescape. Но unescape немного глуповат, поэтому он всегда думает, что один байт - это одно и то же, что и один символ. Что касается unescape, у вас есть два байта, следовательно, у вас есть два символа. Если вы посмотрите кодовые точки для 0xd0 и 0xb4, вы увидите следующее:

0xd0 -> Ð
0xb4 -> ´

Итак, unescape возвращает строку, состоящую из двух символов, Ð и ´ (вместо того, чтобы выяснить, что два байта, которые он получил, на самом деле всего один символ, закодированный в utf-8). Затем, когда вы присваиваете свойство text, вы на самом деле не передаете д´ butд`, и это то, что вы видите в текстовой области.

person Juan Pablo Califano    schedule 31.03.2011
comment
Хотя это отвечает на вышеуказанный вопрос, я считаю, что encodeURIComponent является проблемой, а не выходом. Экранирование кириллического символа дает мне u0434%, который печатается правильно. encodeURIComponent дает мне этот %d0%b4, который интерпретируется как два символа, как вы сказали. Что можно сделать, если вывод encodeURIComponent интерпретируется неправильно? - person Amalgovinus; 31.03.2011
comment
@Амальговинус. Я не уверен, как поступить в этой ситуации (также я не знаю, какая программа/сервер/и т. д. интерпретирует эти символы). У меня были проблемы с кодировкой только с испанскими символами. Все испанские символы имеют кодовые точки ниже 256, поэтому они либо не кодируются, а отправляются как один байт (ISO-8859-1), либо кодируются в utf-8 (например, %f1 или %c3%b1) . Я не уверен, как вы должны отправлять данные, если принимающая программа не понимает utf-8 или iso-8859-1. Вы пробовали utf-16? Если это сработает, возможно, вам придется сделать кодировку самостоятельно. - person Juan Pablo Califano; 31.03.2011
comment
Оказывается, основной причиной было то, как мы извлекали данные удаленно с помощью URLLoader, а затем использовали для них URLDecode. По-видимому, URLDecode не может обрабатывать UTF-16 и интерпретирует его как UTF-8. Вместо этого решение, похоже, использует decodeURI (и меняет несколько других вещей). Спасибо за уделенное время. Также я хотел отредактировать вопрос, а не ваш ответ, извините за это - person Amalgovinus; 01.04.2011
comment
эээ... не 'URLDecode', unescape. XD Да, unescape — чепуха. Прошел полный круг. - person Amalgovinus; 01.04.2011
comment
@Амальговинус. Без проблем. Я рад, что вы нашли решение. Поскольку вы используете URLLoader, в худшем случае вы можете загрузить данные как двоичные и выполнить все необходимое декодирование самостоятельно (но, похоже, вам не нужно этого делать, поскольку вам удалось заставить его работать) - person Juan Pablo Califano; 01.04.2011