Проблема с %uXXXX

WP

^_^
Проблема с %uXXXX

Как известно Javascript escape'ит юникод используя запись вида %uXXXX,
PHP:
$s = 'Kolik%20%u010Dasu%20str%E1v%EDte%20na%20Internetu';
$r = urldecode(preg_replace('~%u([a-f\d]{4})~ei','urlencode(iconv("UTF-16BE","UTF-8",pack("H4","$1")))',$s));
var_dump($r);
//string(33) "Kolik času str�v�te na Internetu"
Оригинал - Kolik času strávíte na Internetu ?

Т.е. символ "á" не перекодируется.

Пожалуйста подскажите кто как решает данную проблему (нужна кошерная функция). На выходе нужно получить UTF-8.

iconv из UCS-2BE дает то же самое что и из UTF-16BE.
 

phprus

Moderator
Команда форума
WP
Если я правильно понимаю то, что сделано в JsHttpRequest, то надо делать так:
PHP:
$r = preg_replace('~%u([a-f\d]{1,4})~ei','iconv("UCS-2BE","UTF-8",pack("n",hexdec("$1")))',$s);
Похоже что в твоем коде проблемы возникают из-за urldecode.
 

SiMM

Новичок
> Kolik%20%u010Dasu%20str%E1v%EDte%20na%20Internetu
А при чём тут UTF-8 или Unicode?
 

WP

^_^
Сорри не то вставил в пример.
<script>document.write(escape("Kde hled&#225;te nej&#269;ast&#283;ji tipy na v&#253;lety?"));</script>

//Kde%20hled%u0423%u0401te%20nej%u0424%uFFFDast%u0424%uFFFDji%20tipy%20na%20v%u0423%u041Dlety%3F

При перекодировании дает ерунду.
string(52) "Kde hledУЁte nejФ&#65533;astФ&#65533;ji tipy na vУНlety?"

phprus
> Похоже что в твоем коде проблемы возникают из-за urldecode.
Стандартный urlencode это просто замена байта на %HEX без манипуляции с кодировкой.
PHP:
$s =' Kde%20hled%u0423%u0401te%20nej%u0424%uFFFDast%u0424%uFFFDji%20tipy%20na%20v%u0423%u041Dlety%3F';
$r = urldecode(preg_replace('~%u([a-f\d]{1,4})~ei','iconv("UCS-2BE","UTF-8",pack("n",hexdec("$1")))',$s));
var_dump($r);
string(53) " Kde hledУЁte nejФ&#65533;astФ&#65533;ji tipy na vУНlety?"
 

WP

^_^
Wicked
<script>document.write(escape("Kde hled&#225;te nej&#269;ast&#283;ji tipy na v&#253;lety?"));</script>

Я ожидал что тот PHP-код будет обращать функцию escape()...
 

Wicked

Новичок
<script>document.write(escape("Kde hled&#225;te nej&#269;ast&#283;ji tipy na v&#253;lety?"));</script>
У меня получилось вот что:
Kde%20hled%E1te%20nej%u010Dast%u011Bji%20tipy%20na%20v%FDlety%3F

010D;LATIN SMALL LETTER C WITH CARON
011B;LATIN SMALL LETTER E WITH CARON

-~{}~ 18.10.07 01:37:

Я ожидал что тот PHP-код будет обращать функцию escape()...
что ты пхп-коду даешь, то он тебе и обращает. В той строчке (Kde%20hled%u0423%u0401te%20nej%u0424%uFFFDast%u0424%uFFFDji%20tipy%20na%20v%u0423%u041Dlety%3F) у тебя черным по белому прописаны именно те мусорные символы, которые ты привел далее.

Так что дело не в пхп-коде. И, что-то мне подсказывает, даже не в работе функции escape();
 

WP

^_^
Wicked
Если не сложно, попробуй у себя в броузере :) Что выдаст escape()?
 

SelenIT

IT-лунатик :)
WP, при кодировке страницы UTF-8 результат такой же, как у Wicked. Обратное преобразование удалось с помощью
PHP:
html_entity_decode(preg_replace('~%u?([a-f\d]{1,4})~ie','"&#".hexdec("$1").";"',$s),ENT_NOQUOTES,"utf-8");
При кодировке страницы Windows-1251 исходный код Javascript-а выглядит как
Код:
<script>document.write(escape("Kde hledГЎte nejДЌastД›ji tipy na vГЅlety?"));</script>
результат чего совпадает с Вашим примером.

Сам скрипт, естественно, в UTF-8.
 

SelenIT

IT-лунатик :)
Gas, по-моему, можно и не заменять, достаточно добавить в рег "?" после "u" (как в моем варианте).
 

WP

^_^
SelenIT
Спасибо! То что нужно.


Спасибо всем, решение найдено.

-~{}~ 18.10.07 02:00:

Конечное решение:
PHP:
$r = urldecode(preg_replace('~%u([a-f\d]{1,4})~ei','urlencode(html_entity_decode("&#".hexdec("$1").";",ENT_NOQUOTES,"utf-8"))',$s))
 

SelenIT

IT-лунатик :)
WP, а зачем еще декодированные подстановки urlencod'ить, а потом обратно urldecod'ить? Разве мой вариант чего-то не учитывает?
 

WP

^_^
SelenIT
Если заescape'ить &amp;#32; то после всех пертурбаций будет пробел а не &amp;#32;
 

SelenIT

IT-лунатик :)
Хм... я как раз понял задачу так, что на выходе нужно раскодировать все подстановки - и стандартные типа того же пробела, и сабжевые...

Но по идее без вопросика в реге пробелы и так задевать не должно, а urlencode-urldecode, имхо, так и так взаимно гасятся...
 

WP

^_^
SelenIT
В исходной строке могут быть также и %xx последовательности.

Раскодировать ничего такого не требовалось, требовалось побайтно раскодировать %XX и %uXXXX в UTF-8
 

SelenIT

IT-лунатик :)
WP, сорри, увидел...

Вот такой вариант регулярки, по-моему, корректно различает оба вида подстановок: '~%(u[a-f\d]{4}|[a-f\d]{2})~ie'
 

WP

^_^
:)) В итоге все %.. и %u.... должны были бы заменены байтами. Фактически свой urldecode(), т.к. javascript шлет такие последовательности.
 

SelenIT

IT-лунатик :)
Мой итоговый вариант:
PHP:
html_entity_decode(preg_replace('~%(u[a-f\d]{4}|[a-f\d]{2})~ie','"&#".hexdec("$1").";"',$s),ENT_NOQUOTES,"utf-8");
 

phprus

Moderator
Команда форума
SelenIT
А если в строке уже есть последовательности &#...; ?

WP
Кстати в первом сообщении я немного не правильно интерпретировал код JsHttpRequest. Так вроде правильно:
PHP:
$s = preg_replace('/%(?!5B)(?!5D)([0-9a-f]{2})/si', '%u00\\1', $src);
$r = preg_replace('~%u([a-f\d]{1,4})~ei','iconv("UCS-2BE","UTF-8",pack("n",hexdec("$1")))',$s);
 
Сверху