x
 
Артём Коротких
5 апреля 2012

Задался вопросом, в какой кодировке всё же лучше делать сайт?

Как выбор кодировки может повлиять на кроссбраузерность или что-нибудь ещё?

И, наконец, как правильно обращаться с кодировкой на страницах или при обращении к БД?



Артём!

Для меня ответ на этот вопрос очевиден: нужно использовать UTF-8.

Изначально программисты разных стран кодировали текст, не думая о том, что в мире есть ещё другие языки со своими символами. Когда цифровой мир объединил интернет, возникла необходимость отображать письма и страницы так, чтобы их можно было прочитать или написать на любом компьютере мира. Так появились кодовые страницы или кодировки. Как метаинформация они прилагались к каждому тексту, говоря браузеру или почтовому клиенту, каким образом расшифровывать байты в печатные символы. Неудивительно, что часто кодировку забывали указать или ошибались с ней. Программам пришлось учиться определять её автоматически, что не всегда удавалось. Стало совершенно очевидно, что миру нужен цифровой Эсперанто. Если в роли обычного языка Эсперанто постиг былинный отказ, то в информационных технологиях он стал панацеей. Только назвали его Юникод.

Самой перспективной версией Юникода стал UTF-8. Он обратносовместим с аски-кодировкой, не ломается, если в строке обнаруживается неправильный символ, и имеет динамический размер кода символа от одного до шести байт.

Есть вещи, которые нужно помнить при работе с Юникодом. Всегда передавайте кодировку с сервера в ХТТП-заголовках и указывайте её в мета-тегах:

<meta charset="UTF-8" />

Помимо хтмлек, нужно убедиться что у файлов с явасксиптами и стилями тоже стоит правильная кодировка. Пример файла .htaccess для Апача:

AddCharset UTF-8 .js
AddCharset UTF-8 .css

Если вы пишете на Руби, то не забывайте ставить в начале файла

# encoding: utf-8

Самые большие проблемы с обработкой UTF-8 в ПХПВо-первых, нужно использовать mb-аналоги строковых функций, например: mb_substr, вместо substr. Для этого модуль mbstring должен быть загружен в рантайм ПХП. Можно даже сразу настроить его на работу с нужной кодировкой:

mb_internal_encoding('UTF-8');
mb_regex_encoding('UTF-8');
Во-вторых, есть определённые проблемы с нелатинскими символами в регулярных выражениях. Например, даже при указании модификатора u, русские буквы не входят в \w, поэтому их надо указывать явно [А-Яа-яЁё] (Код буквы ё не идёт следом за е в таблице, поэтому она добавляется отдельно).

Код, находящий все слова в строке и помещающий их в переменную $matches

preg_match_all('/[А-Яа-яЁё\w]+/u', $string, $matches);

Популярный в вебе Май-эс-ку-эль пятой версии не имеет никаких противопоказаний к использованию Юникода. После соединения с ним просто выполните команду

SET NAMES ‘utf8’ COLLATE ‘utf8_general_ci’

Правильный коллейшн позволяет считать буквы ё, е и все остальные, которые на них похожи, одним и тем же символом. Это значит, что полнотекстовый поиск выдаст одинаковые результаты по запросам «елка» и «ёлка».

Седьмой и восьмой Интернет-эксплореры в русской версии Виндоус Икс-пи передают все русские буквы из адресной строки в кодировке cp1251, независимо от кодировки сайта. Это может причинить неудобства, если вы используете роутер в своём фреймворке. Мне не известен надёжный способ отличить cp1251 и UTF-8 средствами ПХП. Предполагая, что на входе будет кириллица, можно поискать последовательности %d(0|1) плюс любой байт в строке и на основании этого заключить, что это UTF-8.

Когда-то у меня была задача переконвертировать все треклисты альбомов архива CDDB в UTF-8, в 99,9% файлов кодировку правильно определил chardet.

Предлагаю уважаемым советчикам поделиться другими нюансами работы с UTF-8.


P. S.
Это был совет о разработке сайтов. Хотите узнать всё об умной вёрстке, правильных скриптах, грациозной деградации, трюках и работе технолога с дизайнером? Присылайте вопросы.

Поделиться
Отправить

Комментарии

Виталий Чирков
5 апреля 2012

Для автоматической перегрузки функций работы со строками в PHP можно установить значение параметра mbstring.func_overload в 2 или больше. Так жить гораздо проще.

Подробнее — http://ru2.php.net/manual/ru/mbstring.overload.php.

Андрей Полушин
5 апреля 2012

Мартин Дюрст предлагает для различения кодировок распознавать последовательности байт, характерные только для UTF-8: http://www.w3.org/International/questions/qa-forms-utf-8.ru — этот способ распознаёт UTF-8 очень надёжно.

В той же статье указано, от чего зависит кодировка, используемая браузером при передаче данных.

Анатолий Буров
5 апреля 2012

По моим ощущениям люди часто не делают различий между понятиями «набор символов» и «кодировка», а зря. В большинстве кодировок разница, возможно, и невелика, но имея дело с Юникодом, нужно чётко понимать что есть что. Особенно больно по этим граблям ходят изучающие язык Python.

Набор символов (character set) — это некий набор значков, символов, каждому символу приписан номер.

Кодировка (encoding) — это способ представить (т. е. закодировать) последовательность из символов в виде последовательности байтов.

Рассмотрим пару примеров.

В набор символов Windows-1251 (http://en.wikipedia.org/wiki/Windows-1251) входят 256 различных символов со своими номерами. Символ «0» имеет номер 48, символ «R» — номер 82, символ «ы» — 251. Ещё раз — это пока абстрактный набор, просто список, который существует только в головах программистов.

Теперь рассмотрим кодировку Windows-1251. Эта кодировка позволяет представить символы из набора Windows-1251 в виде последовательности байтов. Кодировка устроена очень разумно — берём символ, берём его номер, записываем этот номер в виде байта! Символов 256, номера у них от 0 до 255, поэтому в байт точно влезет! Ура!

Набор символов ASCII содержит всего 128 символов. Кодировка ASCII тоже прямолинейна — берём и пишем в байт номер символа. Кстати, получается, что не всякую последовательность байтов можно считать текстом, закодированным с помощью ASCII: байтами со значением больше 127 никакие символы ASCII не кодируются.

Из-за того, что подобные кодировки записывали символы просто как их номера из набора, разница между этими понятиями была довольно размыта. С Юникодом дело обстоит иначе, здесь эта разница существенна.

Юникод — это набор символов (с номерами), в котором стараются собрать все-все алфавиты и даже больше.

Кодировок для этого набора придумали множество. Кодировка USC-2, например, устроена примерно как и Windows-1251: берём номер символа и записываем его как два байта. Увы, в два байта можно записать только значения от 0 до 65535, то есть USC-2 позволяет закодировать только часть знаков Юникода, да и то довольно накладным образом: любой символ, даже латинский, кодируются двумя байтами.

Кодировка UTF-8 хитрее. Первые 128 символов Юникода совпадают с символами ASCII. Эти символы UTF-8 кодирует как один байт, отсюда обратная совместимость: если мы используем только это подмножество символов, то нет разницы как их кодировать: последовательность байтов, полученных с помощью UTF-8 и ASCII будет совпадать. То есть если взять закодированный ASCII текст, и раскодировать его с помощью UTF-8, то в итоге получится тот же самый текст. Что UTF-8 делает с остальными символами, номера которых в Юникоде больше 128 — это уже отдельная увлекательная тема.

К сожалению, эти понятия иногда путаются даже в стандартах: в элементе в атрибуте «charset» указывается именно кодировка (encoding).

Хорошая статья на эту тему у Джоэла Сполски: http://www.joelonsoftware.com/articles/Unicode.html, очень её рекомендую всем, кто хочет раз и навсегда разобраться в этом предмете и больше никогда не путаться ;)

Евгений Степанищев
5 апреля 2012

Во-первых, проблемы с UTF-8 в ПХП гораздо более глубокие. Один модуль mb_string их не вылечит ни в коем разе. Например, он не даст ничего в случае сортировки (sort, ksort и прочие),
или при использовании функций файловой системы (к примеру dirname), кроме того, он перекрывает даже далеко не все строковые функции (например — strrev). Так что подмена функций модулем mb_string не спасает от проблем, наоборот, она их привносит — нужно всегда помнить какие функции перекрыты, а какие нет.

Во-вторых, что касается регулярных выражений. С незапамятных времён в ПЦРЕ есть конструкции для работы с Юникодом. Например, \pL — все буквы. Использовать их гораздо лучше, чем [А-Яа-яЁё]. Кроме того, в новых версиях ПЦРЕ появились «глаголы» (verbs), один из них — «(*UCP)» позволяет включать в \w и прочие комбинации национальные символы.

Подробнее http://bolknote.ru/2010/09/08/~2704/

Есть и ещё вариант: использовать не ПЦРЕ в регулярках, а тот же mb_string, в его состав входит библиотека «Онигурума», на большинстве используемых регулярок (из-за того, что их язык мало кто знает толком) её мощности хватит, а работает с UTF-8 она быстрее, чем ПЦРЕ.

Подробности: http://bolknote.ru/2010/12/22/~2869/#12 http://bolknote.ru/2010/12/22/~2868

P.S.: Вот тут мой опыт перевода крупоного проекта с cp1251 на UTF-8, «на ходу»: http://bolknote.ru/write/?issue_phputf8

Александр Мядзель
14 апреля 2012

Никто не упомянул т. н.UTF-8 BOM (англ. Byte Order Mark — метку порядка байтов), которая привносит свои «прелести» в работу вашего кода.

Те кто работает с PHP, наверняка знают, что наличие BOM в файле не позволяет отправить заголовки, если явно не включить буферизацию посредством ob_start(). Также, если заинклюдить некий файл между имеющимся HTML-кодом, то BOM вы встретите в месте инклюда, даже если этот файл пустой.

Многие языки на системном уровне (в отличии от PHP) вырезают эту метку, тем самым позволяя забыть о проблемах.

У каждого PHP-разработчика должна быть за пазухой такая функция, вырезающая метку из начала файла

function removeBOM($str) {
if (substr($str, 0, 3) == pack(«CCC», 0xEF,0xBB,0xBF)) {
$str = substr($str, 3);
}

return $str;
}


Кстати, валидатор от W3C посоветует вам убрать ее, если встретит в валидируемом файле.


Цель рубрики — обсуждение вопросов дизайна всех видов, текста в дизайне и взаимоотношений дизайнеров с клиентами.

Мы публикуем комментарии, которые добавляют к уже сказанному новые мысли и хорошие примеры. Мы ожидаем, что такие комментарии составят около 20% от общего числа.

Решение о публикации принимается один раз; мы не имеем возможности комментировать или пересматривать свое решение, хотя оно может быть ошибочно. Уже опубликованные комментарии могут быть удалены через некоторое время, если без них обсуждение не становится менее ценным или интересным.

Вот такой веб 2.0.

Вы используете Зеплин? 1 Несколько месяцев назад меня повысили из обычного разработчика до «тимлида» 1 Как правильно, эффективно и уважительно ставить KPI? Как готовить макеты для технологов? 6




Недавно всплыло

2 Хочу научиться сторителлингу 12 Как совместить информационный стиль и текст для поисковиков? 7 2