\xd0\x98\xd1\x81\xd1\x82\xd0\xbe\xd1\x87\xd0\xbd\xd0\xb8\xd0\xba - Не декодированный UTF. Пример декодирования на python: decodeVar = var.read().decode("utf-8") ������ ��������� ��� ��������� - windows1251 отображенный как utf8. Если из это получаем из бд, то устанавливаем mysql_query("SET NAMES 'utf8'"); РјРїРѕСЂС‚ успешно завершен, запросов выполнено -> CP1251 -> UTF8 -> мпорт успешно завершен, запросов выполнено
Кодировка может находится в 16-ти ричном значение (байткод) или декодирован в символы.
таблица 16-ти ричных значений для windows-1251
Перенос файлов с одного FreeBSD на другой. В файлах сайта присутствовали файлы “электронная ручка DP-305i-b.jpg” и ссылки на файлы не открываются после переноса
Наш отдающий сервер:
$ locale LANG=ru_RU.KOI8-R LC_CTYPE="ru_RU.KOI8-R" LC_COLLATE="ru_RU.KOI8-R" LC_TIME="ru_RU.KOI8-R" LC_NUMERIC="ru_RU.KOI8-R" LC_MONETARY="ru_RU.KOI8-R" LC_MESSAGES="ru_RU.KOI8-R" LC_ALL=
Файл на сервере имеет следящий вид: п░п╨п╨я┐п╪я┐п╩я▐я┌п╬я─ HTC Desire HD 1500_thm.jpg
Наш принимающий сервер:
$ locale LANG= LC_CTYPE="C" LC_COLLATE="C" LC_TIME="C" LC_NUMERIC="C" LC_MONETARY="C" LC_MESSAGES="C" LC_ALL=
Файл на сервере имеет следящий вид: �%90кк�%83м�%83л�%8F�%82о�%80 HTC Desire HD 1500_thm.jpg
1) При помощи декодара видим, что файл п░п╨п╨я┐п╪я┐п╩я▐я┌п╬я─ перекодируется в чистый и хороший текст KOI8-R → UTF-8. Поддерживаемые кодировки Apache можно видеть grep -iRH AddCharset /usr/local/etc/apache22/ # Декодер → http://www.artlebedev.ru/tools/decoder/
2) При помощи декодара видим, что файл �%90кк�%83м�%83л�%8F�%82о�%80 перекодируется в некорректный текст а значит кодировка имени файла уже испорчена.
3) Меняем кодировку для FreeBSD следующим образом:
setenv LANG ru_RU.KOI8-R
4) Несмотря на то, что мы изменили кодировку, имена файлов все равно не изменятся и будут в некорректной кодировки. Следовательно необходимо повторно перенести файлы. При tar -xvf и изменение setenv LANG можно видеть, что имена файлов транслируются в кодировку которая выставлена по умолчанию. Другими словами в архиви мы имеем KOI8-R и она переводится в кодировку сервера и при KOI8-R → UTF-8 или другие то кодировка бьется, а следовательно должна быть KOI8-R → KOI8-R. На Выходе получаем файл на диске нашего сервера с названием “электронная ручка DP-305i-b.jpg”
Файл распознается как
# file -i ac2isp.pl ac2isp.pl: text/x-perl; charset=utf-8
Изменение кодировки сервера и повторное скачивание файлов ни как не повлияло на содержимое файла.
# locale LANG=ru_RU.UTF-8 LC_CTYPE="ru_RU.UTF-8" LC_COLLATE="ru_RU.UTF-8" LC_TIME="ru_RU.UTF-8" LC_NUMERIC="ru_RU.UTF-8" LC_MONETARY="ru_RU.UTF-8" LC_MESSAGES="ru_RU.UTF-8" LC_ALL=
Вывод скрипта все равно выдавал - п©п╣я─п╣п╫п╬я│п╟ я│п╟п╧я┌п╬п╡ п╦ п╠п╟п╥ п╢п╟п╫п╫я▀я┘ KOI8-R → UTF-8 Но при чтение скрипта через браузер, скрипт корректно читался в UTF-8. В итоге, что то устанавливала кодировку содержимого файла в KOI8-R и я не знал причины. (Скачивание скрипта проходило в уже измененной setenv LANG ru_RU.UTF-8 локали). Так как кодировка содержимого не битая, то можно перекодироваться файл. В итоге, кодировка восстановлена:
iconv -f UTF-8 -t KOI8-RU ./ac2isp.pl > ac2isp2.pl Входящая Исходящая
Почему нужно было кодировать из UTF-8 → KOI8-RU я не разобрался, ведь декодер определял KOI8-R → UTF-8, но результат был достигнут.
1. Выяснили, что в базе данных уже хранятся не корректные символы. Выясняли скачиванием дампа из базы данных и нахождения этих символов. Следовательно, символы битые, надо рекурсивно заменять в документе. 2. sed не дал желаемых результатов просто так. Но в конечном итоге были найдены следующие команды: sed -i -e 's/\xD0\x3F/\xD0\x98/g' ./base.sql #тыт мы заменяем HEX последовательность sed -i -e 's/�?/И/g' ./base.sql Как находились эти последовательности: 2.1 Находим строки с битыми символами. 2.2 Выводим эти строки на консоль и суем в hexdump. Пример: head base.sql -n1680 | tail -n1 | awk '{print $(NF-192)}' | hexdump -C 2.3 В hexdump находим последовательность символов отвечающих за символ 2.4 рекурсивно меняем sed-ом ее.
cat base.sql | grep --color "Даже возможность играть против" | awk '{print $(NF-24)}' �?гра cat base.sql | grep --color "Даже возможность играть против" | awk '{print $(NF-24)}' | hexdump -C 00000000 d0 3f d0 b3 d1 80 d0 b0 0a |.?.......| 00000009 Сразу видна последовательность байтов отвечающих за некорректный символ. Получить корректный символ можно на странице http://www.endmemo.com/unicode/unicodeconverter.php
$ iconv -f UTF-8 -t WINDOWS-1251 ./dump.sql | grep "Самые де" | awk '{print $21}' вне�?нему
$ iconv -f UTF-8 -t WINDOWS-1251 ./dump.sql | grep “Самые де” | awk '{print $21}' | hexdump -C
00000000 d0 b2 d0 bd d0 b5 d1 3f d0 bd d0 b5 d0 bc d1 83 |.......?........| 00000010 c2 a0 0a |...| 00000013
Создаем файл test со строкой внешнему и сравниваем: $ cat test | hexdump -C 00000000 d0 b2 d0 bd d0 b5 d1 88 d0 bd d0 b5 d0 bc d1 83 |................| 00000010 0a |.| 00000011
Соответственно, нужно символ d1 3f заменить на d1 88. sed -i -e 's/\xD1\x3F/\xD1\x88/g' ./base.sql
Все былобы хорошо, но базу данных не желательно перекодировать, поэтом символ следует править в базе данных с корявой кодировкой $ cat dump.sql | grep 1377698010 | grep 11 | awk '{print $21}' РІРЅРµС?нему $ cat dump.sql | grep 1377698010 | grep 11 | awk '{print $21}' | iconv -f UTF-8 -t WINDOWS-1251 вне�?нему $ echo "внешнему" | iconv -f WINDOWS-1251 -t UTF-8 внешнему
$ cat dump.sql | grep 1377698010 | grep 11 | awk '{print $21}' | hexdump -C 00000000 d0 a0 d0 86 d0 a0 d0 85 d0 a0 c2 b5 d0 a1 3f d0 |..............?.| 00000010 a0 d0 85 d0 a0 c2 b5 d0 a0 d1 98 d0 a1 d1 93 d0 |................| 00000020 92 c2 a0 0a |....| 00000024
$ echo "внешнему" | iconv -f WINDOWS-1251 -t UTF-8 | hexdump -C 00000000 d0 a0 d0 86 d0 a0 d0 85 d0 a0 c2 b5 d0 a1 e2 82 |................| 00000010 ac d0 a0 d0 85 d0 a0 c2 b5 d0 a0 d1 98 d0 a1 d1 |................| 00000020 93 0a |..| 00000022
Соответственно, нужно 3f d0 заменить на e2 82 ac d0 sed -i -e 's/\x3F\xD0/\xE2\x82\xAC\xD0/g' ./dump.sql
Ошибка:
Illegal mix of collations (cp1251_general_ci,IMPLICIT) and (latin1_swedish_ci,COERCIBLE) for operation 'like' SQL=SELECT id, title, module, position, content, showtitle, params FROM jos_modules WHERE access <= 0 AND title like '������� ��������%' LIMIT 1 SQL = SELECT id, title, module, position, content, showtitle, params FROM jos_modules WHERE access <= 0 AND title like '������� ��������%' LIMIT 1
В базе данных находится корректный utf-8 (но это не важно) По умолчанию, клиент подключается в качестве latin1_swedish_ci, далее он переключается на cp1251_general_ci Решени: Следовательно, перед подключением к базе данных сразу указываем корректную кодировку.
Исходный текст в базе данных:
Итак, Ñкоро закончитÑÑ 2013, по крайне мере, полугодие мы уже прошли, можно обÑудить какие новшеÑтва были введены за прошедший период.
Автоматический декодер определяет как CP1252 → UTF-8. Результат:
Итак, �коро закончит�� 2013, по крайне мере, полугодие мы уже прошли, можно об�удить какие новше�тва были введены за прошедший период.
1252 это latin1. Экспортируем: mysqldump --default-character-set=latin1 base >> ./base_windows1252.sql В полученном дампе получаем: Ð<98>Ñ<82>ак, Ñ<81>коÑ<80>о законÑ<87>иÑ<82>Ñ<81>Ñ<8f> 2013, по кÑ<80>айне меÑ<80>е, полÑ<83>годие мÑ<8b> Ñ<83>же пÑ<80>оÑ<88>ли
Заходим vim и кодируем в utf-8 ( :e ++enc=utf8 ) и получаем корректный текст: """Итак, скоро закончится 2013, по крайне мере, полугодие мы уже прошли, можно обсудить какие новшества были введены за прошедший период. """
Состояние:
дамп в utf8 Импорт дампа происходит в cp1251 и DEFAULT CHARSET=cp1251 При подключение из консоли по --default-character-set=cp1251 и выполнения запроса, запрос возвращает читабельный текст. При подключение к mysql по cp1251 мы получали кодировку в utf8 вместо cp1251.
Проблема:
Нужно хранить и получать данные в cp1251
Теория:
Для базы данных есть следующая информация о подключениях: SET character_set_client = charset_name; //Кодировка клиента в которой мы отдаем данные. Здесь мы не запрашиваем у сервера перекодирования, а наоборот, подсказываем ему информацию о получаемой кодировки. SET character_set_results = charset_name; //Кодировка получаемых результатов. Здесь мы просим сервер выдать результат в определенной кодировки. SET character_set_connection = charset_name; //What character set should the server translate a statement to _AFTER_ receiving it?. Кодировка которая будет в конечном итоге передана MySQL серверу. Если отличается от set_client, то перекодируется в set_connection на стороне MySQL сервера. Если не отличается, то ничего не происходит.
Решение:
Когда мы подключались к серверу MySQL, мы сообщали что все передаваемые данные находятся в UTF8. В конечном итоге, MySQL хранил UTF байты c пометкой о том, что это байты cp1251. Соответственно, кода мы подключались к MySQL серверу и сообщали, что нам нужны cp1251 данные, то сервер возвращал нам байты в UTF, так как считал, что это байты cp1251 и перекодировать их не нужно. Для решения проблемы в дампе можно было указать: SET character_set_client = utf8; // Мы сообщаем серверу, что изначально передаем utf8 SET character_set_results = cp1251; // Мы сообщаем серверу, что когда он получит от нас данные, чтобы он перекодировал их в cp1251 В дампе, мы указываем: DEFAULT CHARSET=cp1251; // Чтобы сервер пометил себе, что таблица содержит cp1251 и когда у таблицы будут запрашивать cp1251, перекодировки не будет, а если запросят utf8, то перекодирует. Обратите внимание, что можно указать кодировку binary, чтобы перекодирования кодировки совсем не происходило.
На сервере база данных (хранение и работа) в winodws-1251
При импорте: Получаем “????????????? ????????????” Вместо русских букв. Следовательно: в первую очередь смотрим в базу данных которую перенесли и таблицу где содержаться русккие буквы. В базе данных, они должны быть корректны. Если нет, то работаем с iconv и находим кодировку которая при импорте будет отображать корректные символы в базе данных.
Соединение с Базой данных (Сопоставление соединения с MySQL) проходит в latin-1, а кодировка баз данных windows-1251 в следствии и получаем “???? ???”. Кодировку соединения можно выставить для всего сервера в my.cnf или для сайта указав после каждого mysql_connect строку: mysql_query('SET NAMES cp1251'); и mysql_query('SET CHARACTER SET cp1251');
После всех этих действий, кодировка соответствует необходимой.
К примеру
echo "привет" | iconv -c -f WINDOWS-1251 -t UTF-8 привет
Тут, TODO
http://www.science.co.il/Language/Character-code.asp?s=1251
http://www.utf8-chartable.de/unicode-utf8-table.pl
file -i mytext.txt #Укажет текущию кодировку файла
konwert
enconv (enca)
iconv
od
convmv #Конвертирует кодировку в названиях файлов.
Мысли вслух - Вероятно, будет использоваться UTF-8 для сохранения. К примеру latin → UTF-8. В итоге, текст получается испорчен, но легко восстановим UTF-8 → latin, так как цифры отвечающие за символ не изменены. Почему UTF-8? Потому, что имеет наибольшое колличество символов. Не имею понятия, что будет при сохранение UTF-8 текста в ACII. Вероятно, символы используеющие цифры за пределами ACII диапозона будут приведены к какому нибудь, единому символу и безвозвратно испорчены.
:e ++enc=windows-1251 :e ++enc=utf-8
Discussion
http://0xcc.net/jsescape/ - отличное преобразование utf8 текста (\u0441 - например)