Иногда бывает так, что мы получаем массив, в котором элементы имеют кодировку, которая нам без надобности. Необходимо преобразовать все элементы массива в нужную нам кодировку. Когда массив одномерный — это не составляет труда. Но когда мы имеем многомерный массив, могут возникнуть трудности — нам ведь надо опускаться на неопределенную глубину. Следующая маленькая функция решит эту тривиальную задачу:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | function iconvArray($inputArray,$newEncoding){ $outputArray=(); if ($newEncoding!=''){ if (!($inputArray)){ foreach ($inputArray as $element){ if (!($element)){ $element=(($element), $newEncoding,$element); } else { $element=iconvArray($element); } $outputArray[]=$element; } } } return $outputArray; } |
Просто и… рекурсивно ;)
17 комментариев
Позволю себе немного отредактировать (справить) твою функцию:
function iconvArray ($inputArray,$newEncoding){
$outputArray=array ();
if ($newEncoding!=''){
if (!empty ($inputArray)){
foreach ($inputArray as $key => $element){
if (!is_array ($element)){
$element=iconv ($newEncoding,mb_detect_encoding ($element),$element);
} else {
$element=$this->iconvArray ($element, $newEncoding);
}
$outputArray[$key]=$element;
}
}
}
return $outputArray;
}
Согласен, моя функция была написана для простых, но не ассоциативных массивов. Мне уже довелось ее переписать, когда я при разработке получал ассоциативный массив. Твою функцию, кстати, можно дополнить изменением кодировки в ключе, т.к. в ассоциативных массивах можно задавать ключи, состоящие из национальных символов (н-р, кириллицы), и, конечно же, рано или поздно, придется столкнуться с такими массивами.
Смутно представляю себе человека, который станет ключи в массивах писать буквами отличными от общепринятой латиницы, и цифрами непохожими на арабские. Разве что какой-то нечеловек, выносящий мозг своими потугами в MSAccess.
Там есть еще пару чисто технических ошибочек, в «iconv» и рекурсивном вызове функции. А вообще ты прав что ключики нужно тоже декодировать.
Peace.
А как насчет использования указателей? Заместо генерации нового массива. Вот пример моей функции
function Decode (&$sVal)
{
if (is_array ($sVal))
{
foreach ($sVal as &$bVal)
{
CAllSplitTest::Decode (&$bVal);
}
}
else
{
$sVal = iconv («utf-8»,LANG_CHARSET,$sVal);
}
}
Один момент — utf-8 здесь не универсально. Причина этому — если данные приходят извне, то они могут быть в совершенно произвольной кодировке. Также, стоит учитывать и то, что кодировка базы данных, из которой приходят данные, тоже может смениться.
Я бы сделал здесь сам себе ещё одно замечание
— mb_detect_encoding (), которую я использую в статье, возвращает значение ASCII, если в качестве параметра ей отправлена строка в какой-нибудь однобайтовой кодировке, типа Windows-1251. Такое поведение mb_detect_encoding () стоит обрабатывать дополнительно.
Да нет, разумеется насчет «utf-8» не универсально =) я скинул пример именно своей функции, а у меня там всё чисто на utf-8, мне текущее определение ни к чему. Мой пример был лишь для наглядности работы с указателями на массивы, дабы не забивать лишнюю память, создавая новые массивы. Особенно, если работаешь с большими дампами.
Стесняюсь спросить, а что означает сие $this->iconvArray ($element, $newEncoding); в девятой строке? Откуда взялся некий объект $this? Или я чего-то не вижу, что видят все остальные?
Не надо стесняться
. Это я забыл подправить функцию, когда копировал её из своего класса
. Спасибо за наводку, я поправил код.
Кстати также замечу, что в случае перекодирования из cp1251 mb_detect_encoding абсолютно бесполезна, потому что всегда вернёт UTF-8, что сводит всю эту функцию к состоянию полной ненужности. А учитывая, что русскоязычных граждан с русскоязычными сайтами интересует прежде всего перекодировка из cp1251 в UTF-8 (например, чтобы получить JSON для AJAX-запросов), то это всё действительно не нужно. Проще знать входящую и исходящую кодировки и тупо так и писать: iconvArray («cp1251», «UTF-8», $_POST);
mb_detect_encoding над cp1251 вернет в качестве результата ASCII, так что здесь тоже можно сориентироваться — добавить условие. В любом случае, mb_ функции для однобайтовых кодировок не предназначены.
В том-то и потеха, что префикс «mb» означает «мультибайт», и всякие однобайтные кодировки просто игнорирует.
Специально попробовал: ASCII возвращает если нет букв. С буквами возвращает непременно UTF-8.
Верно. Если требуется преобразовывать cp1251 моей функцией, то наиболее простым решением будет, конечно, предложенное тобой.
Хорошая функция, свое дело делает. А вот если в исходном массиве в начале стоит буква Ё, ему сносит крышу, как полечить, уважаемые?
Вот пример такого массива:
(
[0] => Ёмкость для воды
)
Полечил, явно указал кодировку $element=iconv ($newEncoding, «UTF-8»,$element);
Как раз писал комментарий в ответ на твой вопрос
. Можно попробовать ещё вот это для определения кодировки. Правда я не пользовался этими скриптами, не могу сказать насколько они корректно определяют кириллицу.