Site Tools


кодировка

Кодировки

\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

OS

(Пример 1) -> Изменение кодировки при переносе файлов между серверами (FreeBSD)

Перенос файлов с одного 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”

Пример 2 -> Скачивание файла и его работа

Файл распознается как

# 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, но результат был достигнут.

DB

Пример 1 -> Символ �? вместо заглавной буквы И

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

Пример 1.2 -> Символ �? вместо буквы ш

$ 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

Пример 2 -> Разные кодировки запросов к БД

Ошибка:

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  
Решени:
Следовательно, перед подключением к базе данных сразу указываем корректную кодировку.

Пример 3 -> Нахождение кодировки

Исходный текст в базе данных:

Итак, скоро закончится 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, по крайне мере, полугодие мы уже прошли, можно обсудить какие новшества были введены за прошедший период. """

Пример 4 -> подключение по MySQL

Состояние:

дамп в 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

  • При скачивание в windows-1251, получаем символы “<D0><BA><D0><B0><D1><86><D0><B8><D0><B5><D0><B9>” Вместо русских букв
  • При скачивание архива в utf-8 русские буквы в дампе отображаются корректно.

При импорте: Получаем “????????????? ????????????” Вместо русских букв. Следовательно: в первую очередь смотрим в базу данных которую перенесли и таблицу где содержаться русккие буквы. В базе данных, они должны быть корректны. Если нет, то работаем с 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

Other

ПО

file -i mytext.txt #Укажет текущию кодировку файла
konwert
enconv (enca)
iconv
od
convmv #Конвертирует кодировку в названиях файлов.

Вопрос:

  • При mysqldump -A, как будут сохранены кодировки с условием, что базы данных находяться в разных кодировках? И будет ли файл испорчен?

Мысли вслух - Вероятно, будет использоваться UTF-8 для сохранения. К примеру latin → UTF-8. В итоге, текст получается испорчен, но легко восстановим UTF-8 → latin, так как цифры отвечающие за символ не изменены. Почему UTF-8? Потому, что имеет наибольшое колличество символов. Не имею понятия, что будет при сохранение UTF-8 текста в ACII. Вероятно, символы используеющие цифры за пределами ACII диапозона будут приведены к какому нибудь, единому символу и безвозвратно испорчены.

VIM Изменение кодировки отображения
:e ++enc=windows-1251
:e ++enc=utf-8

Discussion

Constantin Conovaloff, 2014/09/16 19:11

http://0xcc.net/jsescape/ - отличное преобразование utf8 текста (\u0441 - например)

You could leave a comment if you were logged in.
кодировка.txt · Last modified: 2016/03/27 03:26 by conovaloff

Page Tools