Кодировка utf 8 с bom что это

Кодировка utf 8 с bom что это

Reg.ru: домены и хостинг

Крупнейший регистратор и хостинг-провайдер в России.

Более 2 миллионов доменных имен на обслуживании.

Продвижение, почта для домена, решения для бизнеса.

Более 700 тыс. клиентов по всему миру уже сделали свой выбор.

Бесплатный Курс «Практика HTML5 и CSS3»

Освойте бесплатно пошаговый видеокурс

по основам адаптивной верстки

на HTML5 и CSS3 с полного нуля.

Фреймворк Bootstrap: быстрая адаптивная вёрстка

Пошаговый видеокурс по основам адаптивной верстки в фреймворке Bootstrap.

Научитесь верстать просто, быстро и качественно, используя мощный и практичный инструмент.

Верстайте на заказ и получайте деньги.

Что нужно знать для создания PHP-сайтов?

Ответ здесь. Только самое важное и полезное для начинающего веб-разработчика.

Узнайте, как создавать качественные сайты на PHP всего за 2 часа и 27 минут!

Создайте свой сайт за 3 часа и 30 минут.

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

Вам останется лишь наполнить его нужной информацией и изменить дизайн (по желанию).

Изучите основы HTML и CSS менее чем за 4 часа.

После просмотра данного видеокурса Вы перестанете с ужасом смотреть на HTML-код и будете понимать, как он работает.

Вы сможете создать свои первые HTML-страницы и придать им нужный вид с помощью CSS.

Бесплатный курс «Сайт на WordPress»

Хотите освоить CMS WordPress?

Получите уроки по дизайну и верстке сайта на WordPress.

Научитесь работать с темами и нарезать макет.

Бесплатный видеокурс по рисованию дизайна сайта, его верстке и установке на CMS WordPress!

Хотите изучить JavaScript, но не знаете, как подступиться?

После прохождения видеокурса Вы освоите базовые моменты работы с JavaScript.

Развеются мифы о сложности работы с этим языком, и Вы будете готовы изучать JavaScript на более серьезном уровне.

*Наведите курсор мыши для приостановки прокрутки.

Кодировки: полезная информация и краткая ретроспектива

Данную статью я решил написать как небольшой обзор, касающийся вопроса кодировок.

Мы разберемся, что такое вообще кодировка и немного коснемся истории того, как они появились в принципе.

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

Что такое кодировка?

Т.е. каждый символ, который мы вводим с клавиатуры, либо видим на экране монитора, закодирован определенной последовательностью битов (нулей и единиц). 8 бит, как вы, наверное, знаете, равны 1 байту информации, но об этом чуть позже.

Внешний вид самих символов определяется файлами шрифтов, которые установлены на вашем компьютере. Поэтому процесс вывода на экран текста можно описать как постоянное сопоставление последовательностей нулей и единиц каким-то конкретным символам, входящим в состав шрифта.

Прародителем всех современных кодировок можно считать ASCII.

Кодировка utf 8 с bom что это. . Кодировка utf 8 с bom что это фото. Кодировка utf 8 с bom что это-. картинка Кодировка utf 8 с bom что это. картинка . Reg.ru: домены и хостинг

Эта аббревиатура расшифровывается как American Standard Code for Information Interchange (американская стандартная кодировочная таблица для печатных символов и некоторых специальных кодов).

Это однобайтовая кодировка, в которую изначально заложено всего 128 символов: буквы латинского алфавита, арабские цифры и т.д.

Кодировка utf 8 с bom что это. 1 ascii. Кодировка utf 8 с bom что это фото. Кодировка utf 8 с bom что это-1 ascii. картинка Кодировка utf 8 с bom что это. картинка 1 ascii. Reg.ru: домены и хостинг

Позже она была расширена (изначально она не использовала все 8 бит), поэтому появилась возможность использовать уже не 128, а 256 (2 в 8 степени) различных символов, которые можно закодировать в одном байте информации.

Такое усовершенствование позволило добавлять в ASCII символы национальных языков, помимо уже существующей латиницы.

Следующим шагом в развитии кодировок можно считать появление так называемых ANSI-кодировок.

По сути это были те же расширенные версии ASCII, однако из них были удалены различные псевдографические элементы и добавлены символы типографики, для которых ранее не хватало «свободных мест».

Примером такой ANSI-кодировки является всем известная Windows-1251. Помимо типографических символов, в эту кодировку также были включены буквы алфавитов языков, близких к русскому (украинский, белорусский, сербский, македонский и болгарский).

Кодировка utf 8 с bom что это. 2 windows1251. Кодировка utf 8 с bom что это фото. Кодировка utf 8 с bom что это-2 windows1251. картинка Кодировка utf 8 с bom что это. картинка 2 windows1251. Reg.ru: домены и хостинг

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

Кодировка utf 8 с bom что это. . Кодировка utf 8 с bom что это фото. Кодировка utf 8 с bom что это-. картинка Кодировка utf 8 с bom что это. картинка . Reg.ru: домены и хостинг

Возникновение всех этих проблем послужило стимулом для создания чего-то нового. Это должна была быть кодировка, которая могла бы кодировать любой язык в мире (ведь с помощью однобайтовых кодировок при всем желании нельзя описать все символы, скажем, китайского языка, где их явно больше, чем 256), любые дополнительные спецсимволы и типографику.

Одним словом, нужно было создать универсальную кодировку, которая решила бы проблему кракозябров раз и навсегда.

Юникод — универсальная кодировка текста (UTF-32, UTF-16 и UTF-8)

Сам стандарт был предложен в 1991 году некоммерческой организацией «Консорциум Юникода» (Unicode Consortium, Unicode Inc.), и первым результатом его работы стало создание кодировки UTF-32.

Кстати, сама аббревиатура UTF расшифровывается как Unicode Transformation Format (Формат Преобразования Юникод).

В этой кодировке для кодирования одного символа предполагалось использовать аж 32 бита, т.е. 4 байта информации. Если сравнивать это число с однобайтовыми кодировками, то мы придем к простому выводу: для кодирования 1 символа в этой универсальной кодировке нужно в 4 раза больше битов, что «утяжеляет» файл в 4 раза.

Очевидно также, что количество символов, которое потенциально могло быть описано с помощью данной кодировки, превышает все разумные пределы и технически ограничено числом, равным 2 в 32 степени. Понятно, что это был явный перебор и расточительство с точки зрения веса файлов, поэтому данная кодировка не получила распространения.

Как очевидно из названия, в этой кодировке один символ кодируют уже не 32 бита, а только 16 (т.е. 2 байта). Очевидно, это делает любой символ вдвое «легче», чем в UTF-32, однако и вдвое «тяжелее» любого символа, закодированного с помощью однобайтовой кодировки.

Количество символов, доступное для кодирования в UTF-16 равно, как минимум, 2 в 16 степени, т.е. 65536 символов. Вроде бы все неплохо, к тому же окончательная величина кодового пространства в UTF-16 была расширена до более, чем 1 миллиона символов.

Однако и данная кодировка до конца не удовлетворяла потребности разработчиков. Скажем, если вы пишете, используя исключительно латинские символы, то после перехода с расширенной версии кодировки ASCII к UTF-16 вес каждого файла увеличивался вдвое.

В результате, была предпринята еще одна попытка создания чего-то универсального, и этим чем-то стала всем нам известная кодировка UTF-8.

Дело в том, что UTF-8 обеспечивает наилучшую совместимость со старыми системами, использовавшими 8-битные символы. Для кодирования одного символа в UTF-8 реально используется от 1 до 4 байт (гипотетически можно и до 6 байт).

В UTF-8 все латинские символы кодируются 8 битами, как и в кодировке ASCII. Иными словами, базовая часть кодировки ASCII (128 символов) перешла в UTF-8, что позволяет «тратить» на их представление всего 1 байт, сохраняя при этом универсальность кодировки, ради которой все и затевалось.

Итак, если первые 128 символов кодируются 1 байтом, то все остальные символы кодируются уже 2 байтами и более. В частности, каждый символ кириллицы кодируется именно 2 байтами.

Таким образом, мы получили универсальную кодировку, позволяющую охватить все возможные символы, которые требуется отобразить, не «утяжеляя» без необходимости файлы.

Если вы работали с текстовыми редакторами (редакторами кода), например Notepad++, phpDesigner, rapid PHP и т.д., то, вероятно, обращали внимание на то, что при задании кодировки, в которой будет создана страница, можно выбрать, как правило, 3 варианта:

— ANSI
— UTF-8
— UTF-8 без BOM

Кодировка utf 8 с bom что это. 3 notepad. Кодировка utf 8 с bom что это фото. Кодировка utf 8 с bom что это-3 notepad. картинка Кодировка utf 8 с bom что это. картинка 3 notepad. Reg.ru: домены и хостинг

Кодировка utf 8 с bom что это. 4 php designer. Кодировка utf 8 с bom что это фото. Кодировка utf 8 с bom что это-4 php designer. картинка Кодировка utf 8 с bom что это. картинка 4 php designer. Reg.ru: домены и хостинг

Кодировка utf 8 с bom что это. 5 rapid php. Кодировка utf 8 с bom что это фото. Кодировка utf 8 с bom что это-5 rapid php. картинка Кодировка utf 8 с bom что это. картинка 5 rapid php. Reg.ru: домены и хостинг

Итак, что же такое BOM и почему нам это не нужно?

BOM расшифровывается как Byte Order Mark. Это специальный Unicode-символ, используемый для индикации порядка байтов текстового файла. По спецификации его использование не является обязательным, однако если BOM используется, то он должен быть установлен в начале текстового файла.

Не будем вдаваться в детали работы BOM. Для нас главный вывод следующий: использование этого служебного символа вместе с UTF-8 мешает программам считывать кодировку нормальным образом, в результате чего возникают ошибки в работе скриптов.

Поэтому, при работе с UTF-8 используйте именно вариант «UTF-8 без BOM». Также лучше не используйте редакторы, в которых в принципе нельзя указать кодировку (скажем, Блокнот из стандартных программ в Windows).

Кодировка текущего файла, открытого в редакторе кода, как правило, указывается в нижней части окна.

Кодировка utf 8 с bom что это. 6 notepad. Кодировка utf 8 с bom что это фото. Кодировка utf 8 с bom что это-6 notepad. картинка Кодировка utf 8 с bom что это. картинка 6 notepad. Reg.ru: домены и хостинг

Обратите внимание, что запись «ANSI as UTF-8» в редакторе Notepad++ означает то же самое, что и «UTF-8 без BOM». Это одно и то же.

Кодировка utf 8 с bom что это. 7 php designer. Кодировка utf 8 с bom что это фото. Кодировка utf 8 с bom что это-7 php designer. картинка Кодировка utf 8 с bom что это. картинка 7 php designer. Reg.ru: домены и хостинг

Кодировка utf 8 с bom что это. 7 1 php designer. Кодировка utf 8 с bom что это фото. Кодировка utf 8 с bom что это-7 1 php designer. картинка Кодировка utf 8 с bom что это. картинка 7 1 php designer. Reg.ru: домены и хостинг

В программе phpDesigner нельзя сразу точно сказать, используется BOM, или нет. Для этого нужно кликнуть правой кнопкой мыши по надписи «UTF-8», после чего во всплывающем окне можно увидеть, используется ли BOM (опция Save with BOM).

Кодировка utf 8 с bom что это. 8 rapid php. Кодировка utf 8 с bom что это фото. Кодировка utf 8 с bom что это-8 rapid php. картинка Кодировка utf 8 с bom что это. картинка 8 rapid php. Reg.ru: домены и хостинг

В редакторе rapid PHP кодировка UTF-8 без BOM обозначается как «UTF-8*».

Как вы понимаете, в разных редакторах все выглядит немного по-разному, однако главную идею вы поняли.

После того, как документ сохранен в UTF-8 без BOM, нужно также убедиться, что верная кодировка указана в специальном метатэге в секции head вашего html-документа:

Соблюдение этих простых правил уже позволит вам избежать многих пробелем с кодировками.

На этом все, надеюсь, что данный небольшой экскурс и пояснения помогли вам лучше понять, что такое кодировки, какие они бывают и как работают.

Если вам интересна эта тема с более прикладной точки зрения, то рекомендую вам изучить мой видеоурок Полный UTF-8: чеклист для начинающих.

P.S. Присмотритесь к премиум-урокам по различным аспектам сайтостроения, а также к бесплатному курсу по созданию своей CMS-системы на PHP с нуля. Все это поможет вам быстрее и проще освоить различные технологии веб-разработки.

Понравился материал и хотите отблагодарить?
Просто поделитесь с друзьями и коллегами!

Источник

Символы Unicode: о чём должен знать каждый разработчик

Кодировка utf 8 с bom что это. f8ojbrekuhscl9trjum rmga9we. Кодировка utf 8 с bom что это фото. Кодировка utf 8 с bom что это-f8ojbrekuhscl9trjum rmga9we. картинка Кодировка utf 8 с bom что это. картинка f8ojbrekuhscl9trjum rmga9we. Reg.ru: домены и хостинг

Если вы пишете международное приложение, использующее несколько языков, то вам нужно кое-что знать о кодировке. Она отвечает за то, как текст отображается на экране. Я вкратце расскажу об истории кодировки и о её стандартизации, а затем мы поговорим о её использовании. Затронем немного и теорию информатики.

Введение в кодировку

Компьютеры понимают лишь двоичные числа — нули и единицы, это их язык. Больше ничего. Одно число называется байтом, каждый байт состоит из восьми битов. То есть восемь нулей и единиц составляют один байт. Внутри компьютеров всё сводится к двоичности — языки программирования, движений мыши, нажатия клавиш и все слова на экране. Но если статья, которую вы читаете, раньше была набором нулей и единиц, то как двоичные числа превратились в текст? Давайте разберёмся.

Краткая история кодировки

На заре своего развития интернет был исключительно англоязычным. Его авторам и пользователям не нужно было заботиться о символах других языков, и все нужды полностью покрывала кодировка American Standard Code for Information Interchange (ASCII).

ASCII — это таблица сопоставления бинарных обозначений знакам алфавита. Когда компьютер получает такую запись:

то с помощью ASCII он преобразует её во фразу «Hello world».

Один байт (восемь бит) был достаточно велик, чтобы вместить в себя любую англоязычную букву, как и управляющие символы, часть из которых использовалась телепринтерами, так что в те годы они были полезны (сегодня уже не особо). К управляющим символам относился, например 7 (0111 в двоичном представлении), который заставлял компьютер издавать сигнал; 8 (1000 в двоичном представлении) — выводил последний напечатанный символ; или 12 (1100 в двоичном представлении) — стирал весь написанный на видеотерминале текст.

В те времена компьютеры считали 8 бит за один байт (так было не всегда), так что проблем не возникало. Мы могли хранить все управляющие символы, все числа и англоязычные буквы, и даже ещё оставалось место, поскольку один байт может кодировать 255 символов, а для ASCII нужно только 127. То есть неиспользованными оставалось ещё 128 позиций в кодировке.

Вот как выглядит таблица ASCII. Двоичными числами кодируются все строчные и прописные буквы от A до Z и числа от 0 до 9. Первые 32 позиции отведены для непечатаемых управляющих символов.

Кодировка utf 8 с bom что это. image loader. Кодировка utf 8 с bom что это фото. Кодировка utf 8 с bom что это-image loader. картинка Кодировка utf 8 с bom что это. картинка image loader. Reg.ru: домены и хостинг

Проблемы с ASCII

Позиции со 128 по 255 были пустыми. Общественность задумалась, чем их заполнить. Но у всех были разные идеи. Американский национальный институт стандартов (American National Standards Institute, ANSI) формулирует стандарты для разных отраслей. Там утвердили позиции ASCII с 0 по 127. Их никто не оспаривал. Проблема была с остальными позициями.

Вот чем были заполнены позиции 128-255 в первых компьютерах IBM:

Кодировка utf 8 с bom что это. image loader. Кодировка utf 8 с bom что это фото. Кодировка utf 8 с bom что это-image loader. картинка Кодировка utf 8 с bom что это. картинка image loader. Reg.ru: домены и хостинг

Какие-то загогулины, фоновые иконки, математические операторы и символы с диакретическим знаком вроде é. Но разработчики других компьютерных архитектур не поддержали инициативу. Всем хотелось внедрить свою собственную кодировку во второй половине ASCII.

Все эти различные концовки назвали кодовыми страницами.

Что такое кодовые страницы ASCII?

Здесь собрана коллекция из более чем 465 разных кодовых страниц! Существовали разные страницы даже в рамках какого-то одного языка, например, для греческого и китайского. Как можно было стандартизировать этот бардак? Или хотя бы заставить его работать между разными языками? Или между разными кодовыми страницами для одного языка? В языках, отличающихся от английского? У китайцев больше 100 000 иероглифов. ASCII даже не может всех их вместить, даже если бы решили отдать все пустые позиции под китайские символы.

Эта проблема даже получила название Mojibake (бнопня, кракозябры). Так говорят про искажённый текст, который получается при использовании некорректной кодировки. В переводе с японского mojibake означает «преобразование символов».

Кодировка utf 8 с bom что это. image loader. Кодировка utf 8 с bom что это фото. Кодировка utf 8 с bom что это-image loader. картинка Кодировка utf 8 с bom что это. картинка image loader. Reg.ru: домены и хостинг

Пример бнопни (кракозябров).

Безумие какое-то.

Именно! Не было ни единого шанса надёжно преобразовывать данные. Интернет — это лишь монструозное соединение компьютеров по всему миру. Представьте, что все страны решили использовать собственные стандарты. Например, греческие компьютеры принимают только греческий язык, а английские отправляют только английский. Это как кричать в пустой пещере, тебя никто не услышит.

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

��� Если только ������ вы не хотели ��� бы ��� читать подобные параграфы. �֎֏0590֐��׀ׁׂ׃ׅׄ׆ׇ

Так появился Unicode

Unicode расшифровывают как Universal Coded Character Set (UCS), и у него есть официальное обозначение ISO/IEC 10646. Но обычно все используют название Unicode.

Этот стандарт помог решить проблемы, возникавшие из-за кодировки и кодовых страниц. Он содержит множество кодовых пунктов (кодовых точек), присвоенных символам из языков и культур со всего мира. То есть Unicode — это набор символов. С его помощью можно сопоставить некую абстракцию с буквой, на которую мы хотим ссылаться. И так сделано для каждого символа, даже египетских иероглифов.

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

Префикс U+ говорит о том, что это стандарт Unicode, а число — это результат преобразования двоичных чисел. Стандарт использует шестнадцатеричную нотацию, которая является упрощённым представлением двоичных чисел. Здесь вы можете ввести в поле что угодно и посмотреть, как это будет преобразовано в Unicode. А здесь можно полюбоваться на все 143 859 кодовых пунктов.

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

Осталось добавить последний ингредиент.

Unicode Transform Protocol (UTF)

UTF — протокол кодирования кодовых пунктов в Unicode. Он прописан в стандарте и позволяет кодировать любой кодовый пункт. Однако существуют разные типы UTF. Они различаются количеством байтов, используемых для кодировки одного пункта. В UTF-8 используется один байт на пункт, в UTF-16 — два байта, в UTF-32 — четыре байта.

Но если у нас есть три разные кодировки, то как узнать, какая из них применяется в конкретном файле? Для этого используют маркер последовательности байтов (Byte Order Mark, BOM), который ещё называют сигнатурой кодировки (Encoding Signature). BOM — это двухбайтный маркер в начале файл, который говорит о том, какая именно кодировка тут применена.

В интернете чаще всего используют UTF-8, она также прописана как предпочтительная в стандарте HTML5, так что уделю ей больше всего внимания.

Кодировка utf 8 с bom что это. image loader. Кодировка utf 8 с bom что это фото. Кодировка utf 8 с bom что это-image loader. картинка Кодировка utf 8 с bom что это. картинка image loader. Reg.ru: домены и хостинг

Этот график построен в 2012-м, UTF-8 становилась доминирующей кодировкой. И всё ещё ею является.

Кодировка utf 8 с bom что это. image loader. Кодировка utf 8 с bom что это фото. Кодировка utf 8 с bom что это-image loader. картинка Кодировка utf 8 с bom что это. картинка image loader. Reg.ru: домены и хостинг

Что такое UTF-8 и как она работает?

UTF-8 кодирует с помощью одного байта каждый кодовый пункт Unicode с 0 по 127 (как в ASCII). То есть если вы писали программу с использованием ASCII, а ваши пользователи применяют UTF-8, они не заметят ничего необычного. Всё будет работать как задумано. Обратите внимание, как это важно. Нам нужно было сохранить обратную совместимость с ASCII в ходе массового внедрения UTF-8. И эта кодировка ничего не ломает.

Как следует из названия, кодовый пункт состоит из 8 битов (один байт). В Unicode есть символы, которые занимают несколько байтов (вплоть до 6). Это называют переменной длиной. В разных языках удельное количество байтов разное. В английском — 1, европейские языки (с латинским алфавитом), иврит и арабский представлены с помощью двух байтов на кодовый пункт. Для китайского, японского, корейского и других азиатских языков используют по три байта.

Если нужно, чтобы символ занимал больше одного байта, то применяется битовая комбинация, обозначающая переход — он говорит о том, что символ продолжается в нескольких следующих байтах.

И теперь мы, как по волшебству, пришли к соглашению, как закодировать шумерскую клинопись (Хабр её не отображает), а также значки emoji!

Подытожив сказанное: сначала читаем BOM, чтобы определить версию кодировки, затем преобразуем файл в кодовые пункты Unicode, а потом выводим на экран символы из набора Unicode.

Напоследок про UTF

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

Если HTML-документ не содержит упоминания кодировки, спецификация HTML5 предлагает такое интересное решение, как BOM-сниффинг. С его помощью мы по маркеру порядка байтов (BOM) можем определить используемую кодировку.

Это всё?

Unicode ещё не завершён. Как и в случае с любым стандартом, мы что-то добавляем, убираем, предлагаем новое. Никакие спецификации нельзя назвать «завершёнными». Обычно в год бывает 1-2 релиза, найти их описание можно здесь.

Если вы дочитали до конца, то вы молодцы. Предлагаю сделать домашнюю работу. Посмотрите, как могут ломаться сайты при использовании неправильной кодировки. Я воспользовался этим расширением для Google Chrome, поменял кодировку и попытался открывать разные страницы. Информация была совершенно нечитаемой. Попробуйте сами, как выглядит бнопня. Это поможет понять, насколько важна кодировка.

Кодировка utf 8 с bom что это. image loader. Кодировка utf 8 с bom что это фото. Кодировка utf 8 с bom что это-image loader. картинка Кодировка utf 8 с bom что это. картинка image loader. Reg.ru: домены и хостинг

Заключение

При написании этой статьи я узнал о Майкле Эверсоне. С 1993 года он предложил больше 200 изменений в Unicode, добавил в стандарт тысячи символов. По состоянию на 2003 год он считался самым продуктивным участником. Он один очень сильно повлиял на облик Unicode. Майкл — один из тех, кто сделал интернет таким, каким мы его сегодня знаем. Очень впечатляет.

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

Источник

Грустная история забытых символов. Как не сойти с ума при работе с кодировками в C++

Кодировка utf 8 с bom что это. e519e91687424ad58b7e3fe28debe2b9. Кодировка utf 8 с bom что это фото. Кодировка utf 8 с bom что это-e519e91687424ad58b7e3fe28debe2b9. картинка Кодировка utf 8 с bom что это. картинка e519e91687424ad58b7e3fe28debe2b9. Reg.ru: домены и хостинг

Говоря о тексте, большинство программистов C++ думают о массивах кодов символов и кодировке, которой эти коды соответствуют. Наиболее опытные разработчики вообще не мыслят понятие текста без указания кодировки, наименее опытные просто считают массив байтов с кодами символов данностью и интерпретируют в понятиях кодировки операционной системы. Фундаментальная разница между этими двумя подходами не только в опыте разработчика, но и в том, что не думать о кодировке намного проще. Пора рассмотреть способ, как не заботиться о хранении кодировки, перекодировке текста, получать свободный доступ к символам и при этом видеть безошибочное представление текста вне зависимости от того, кто и где смотрит на строку текста: в Китае ли, в США или на острове Мадагаскар.

8 бит и все-все-все…

Начнем с главного. Создатели языка си были минималистами. По сей день в стандарте C/C++ не предусмотрено типа «байт». Вместо этого типа используется тип char. Char означает character, иными словами — символ. Соответственно, говоря в С/С++ о типе char, мы подразумеваем «байт», и наоборот. Вот тут и начинается самое интересное. Дело в том, что максимально возможное число символов, кодируемых 8 битами, равно 256, и это при том, что на сегодняшний день в таблице Unicode насчитываются сотни тысяч символов.

Хитрые создатели ASCII-кодов сразу же зарезервировали первые 128 кодов под стандартные символы, которыми смело можно закодировать практически все в англоязычном мире, оставив нам лишь половину байта под свои нужды, а точнее лишь один свободный старший бит. В результате в первые годы становления информатики все пытались ужаться в эти оставшиеся «отрицательные» числа от –128 до –1. Каждый набор кодов стандартизировался под определенным именем и с этого момента именовался кодировкой. В какой-то момент кодировок стало больше, чем символов в байте, и все они были несовместимы между собой в той части, что выходила за пределы первых 128 ASCII-символов. В результате, если не угадать с кодировкой, все, что не являет собой набор символов первой необходимости для американского сообщества, будет отображено в виде так называемых кракозябр, символов, как правило, вообще нечитаемых.

Мало того, для одних и тех же алфавитов разные системы вводили кодировки, совершенно рассогласованные между собой, даже если это две системы за авторством одной компании. Так, для кириллицы в MS DOS использовались кодировки 855 и 866, а для Windows уже 1251, все для той же кириллицы в Mac OS используется уже своя кодировка, особняком от них стоят KOI8 и KOI7, есть даже ISO 8859-5, и все будут трактовать одни и те же наборы char совершенно разными символами. Мало того, что было невозможно при обработке различных байт-символов пользоваться сразу несколькими кодировками, например при переводе с русского на немецкий с умлаутами, вдобавок сами символы в некоторых алфавитах ну никак не хотели помещаться в оставленные для них 128 позиций. В результате в интернациональных программах символы могли интерпретироваться в разных кодировках даже в соседних строках, приходилось запоминать, какая строка в какой кодировке, что неизбежно вело к ошибкам отображения текста, от забавных до совсем не смешных.

Поставь себе на виртуальную машину любую другую операционную систему с другой кодировкой по умолчанию, нежели на твоей хостовой системе, например Windows c кодировкой 1251, если у тебя Linux с UTF-8 по умолчанию, и наоборот. Попробуй написать код с выводом строки кириллицей в std::cout, который без изменения кода будет собираться и работать под обеими системами одинаково. Согласись, интернационализация кросс-платформенного кода не такая простая задача.

Пришествие Юникода

Задумка Юникода была проста. Каждому символу раз и навсегда присваивается один код на веки вечные, это стандартизуется в очередной версии спецификации таблицы символов Юникода, и код символа уже не ограничен одним байтом. Великолепная задумка во всем, кроме одного: в языки программирования C/C++ и не только в них символ char раз и навсегда ассоциировался с байтом. Повсюду в коде подразумевался sizeof(char), равный единице. Строки текста же были обычными последовательностями этих самых char, заканчивающимися символом с нулевым кодом. В защиту создателей языка си, Ритчи и Кернигана, следует сказать, что в те далекие 70-е годы никто и подумать не мог, что для кодирования символа понадобится так много кодов, ведь для кодирования символов печатной машинки вполне хватало и байта. Как бы то ни было, основное зло было сотворено, любое изменение типа char привело бы к потере совместимости с уже написанным кодом. Разумным решением стало введение нового типа «широкого символа» wchar_t и дублирование всех стандартных функций языка си для работы с новыми, «широкими» строками. Контейнер стандартной библиотеки C++ string также обрел «широкого» собрата wstring.

Все рады и счастливы, если бы не одно «но»: все уже привыкли писать код на основе байтовых строк, а префикс L перед строковым литералом не добавлял энтузиазма разработчикам на C/C++. Люди предпочитали не использовать символы за пределами ASCII и смириться с ограниченностью латиницы, чем писать непривычные конструкции, несовместимые с уже написанным кодом, работавшим с типом char. Осложняло ситуацию то, что wchar_t не имеет стандартизированного размера: например, в современных GCC-компиляторах g++ он 4 байта, в Visual C++ — 2 байта, а разработчики Android NDK урезали его до одного байта и сделали неотличимым от char. Получилось так себе решение, которое работает далеко не везде. С одной стороны, 4-байтный wchar_t наиболее близок к правде, так как по стандарту один wchar_t должен соответствовать одному символу Юникода, с другой стороны, никто не гарантирует, что будет именно 4 байта в коде, использующем wchar_t.

Альтернативным решением стала однобайтовая кодировка UTF-8, которая мало того, что совместима с ASCII (старший бит, равный нулю, отвечает за однобайтовые символы), так еще и позволяет кодировать вплоть до 4-байтового целого, то есть свыше 2 миллиардов символов. Плата, правда, довольно существенная, символы получаются различного размера, и чтобы, например, заменить латинский символ R на русский символ Я, потребуется полностью перестроить всю строку, что значительно дороже обычной замены кода в случае 4-байтового wchar_t. Таким образом, любая активная работа с символами строки в UTF-8 может поставить крест на идее использовать данную кодировку. Тем не менее кодировка довольно компактно ужимает текст, содержит защиту от ошибок чтения и, главное, интернациональна: любой человек в любой точке мира увидит одни и те же символы из таблицы Юникода, если будет читать строку, закодированную в UTF-8. Конечно, за исключением случая, когда пытается интерпретировать эту строку в другой кодировке, все помнят «кракозябры» при попытке открыть кириллицу в UTF-8 как текст в кодировке по умолчанию в Windows 1251.

Устройство однобайтного Юникода

Устроена кодировка UTF-8 весьма занятно. Вот основные принципы:

Как раз 0x42F — код символа Я в таблице символов Юникода.

Другими словами, если не работать с символами в строке, заменяя их другими символами из таблицы Юникода, то можно использовать кодировку UTF-8, она надежна, компактна и совместима с типом char в том плане, что элементы строк совпадают по размеру с байтом, но не обязательно являются при этом символами.

Собственно, именно эффективностью и популярностью кодировки UTF-8 и обусловлено насильственное введение однобайтового wchar_t в Android NDK, разработчики призывают использовать UTF-8, а «широкие» строки не признают как жизнеспособный вид. С другой стороны, Google не так давно отрицал даже исключения в C++, однако весь мир не переспоришь, будь ты хоть трижды Google, и обработку исключений пришлось поддержать. Что касается wchar_t символов с размером в один байт, то множество библиотек уже привыкло к мытарствам с типом wchar_t и дублируют «широкий» функционал обработкой обычных байтовых строк.

UTF (Unicode Transformation Format) — по сути байтовое представление текста, использующее коды символов из таблицы Юникода, запакованные в байтовый массив согласно стандартизированным правилам. Наиболее популярны UTF-8 и UTF-16, которые представляют символы элементами по 8 бит и по 16 бит соответственно. В обоих случаях символ совершенно необязательно занимает ровно 8 или 16 бит, например, в UTF-16 используются суррогатные пары, по сути пары 16-битных значений, используемых вместе. В результате значащих битов становится меньше (20 в случае суррогатной пары), чем битов в группе представляющих символ, но возможности кодировать символы начинают превышать ограничения в 256 или 65 536 значений, и можно закодировать любой символ из таблицы Юникода. Выгодно отличающийся от собратьев UTF-32 менее популярен, ввиду избыточности представления данных, что критично при большом объеме текста.

Пишем по-русски в коде

Беды и дискриминация по языковому признаку начинаются, когда мы пытаемся использовать в коде строку на языке, отличном от ASCII. Так, Visual Studio под Windows создает все файлы в кодировке файловой системы по умолчанию (1251), и при попытке открыть код со строками по-русски в том же Linux с кодировкой по умолчанию UTF-8 получим кучу непонятных символов вместо исходного текста.

Ситуацию частично спасает пересохранение исходников в кодировке UTF-8 с обязательным символом BOM, без него Visual Studio начинает интерпретировать «широкие» строки с кириллицей весьма своеобразно. Однако, указав BOM (Byte Order Mark — метка порядка байтов) кодировки UTF-8 — символ, кодируемый тремя байтами 0xEF, 0xBB и 0xBF, мы получаем узнавание кодировки UTF-8 в любой системе.

BOM — стандартный заголовочный набор байтов, нужный для распознавания кодировке текста в Юникоде, для каждой из кодировок UTF он выглядит по-разному. Не стесняйся использовать родной язык в программе. Даже если тебе придется локализовывать ее в другие страны, механизмы интернационализации помогут превратить любую строку на одном языке в любую строку на другом. Разумеется, это в случае, если продукт разрабатывается в русскоязычном сегменте.

Старайся использовать «широкие» строки как для строковых констант, так и для хранения и обработки промежуточных текстовых значений. Эффективная замена символов, а также совпадение количества элементов в строке с количеством символов дорогого стоит. Да, до сих пор не все библиотеки научились работать с «широкими» символами, даже в Boost попадается целый ряд библиотек, где поддержка широких строк сделана небрежно, но ситуация исправляется, во многом благодаря разработчикам, пишущим ошибки в трекер библиотеки, не стесняйся и ты фиксировать ошибки на сайте разработчика библиотеки.

Писать константы и переменные, а также названия функций кириллицей все же не нужно. Одно дело — выводить константы на родном языке, совсем другое — писать код, постоянно переключая раскладку. Не самый лучший вариант.

Различаем тип «байты» и тип «текст»

Главное, что нужно уметь и иметь в виду, — что тип «текст» в корне отличается от типа «набор байтов». Если мы говорим о строке сообщения, то это текст, а если о текстовом файле в некоторой кодировке, то это набор байтов, который можно вычитать как текст. Если по сети нам приходят текстовые данные, то они приходят к нам именно байтами, вместе с указанием кодировки, как из этих байтов получить текст.

Если посмотреть на Python 3 в сравнении с Python 2, то третья версия совершила по-настоящему серьезный скачок в развитии, разделив эти два понятия. Крайне рекомендую даже опытному C/C++ разработчику поработать немного в Python 3, чтобы ощутить всю глубину, с которой произошло разделение текста и байтов на уровне языка в Python. Фактически текст в Python 3 отделен от понятия кодировки, что для разработчика C/C++ звучит крайне непривычно, строки в Python 3 отображаются одинаково в любой точке мира, и если мы хотим работать с представлением этой строки в какой-либо кодировке, то придется преобразовать текст в набор байтов, с указанием кодировки. При этом внутреннее представление объекта типа str, по сути, не так важно, как понимание, что внутреннее представление сохранено в Юникоде и готово к преобразованию в любую кодировку, но уже в виде набора байтов типа bytes.

В C/C++ подобный механизм нам мешает ввести отсутствие такой роскоши, как потеря обратной совместимости, которую позволил себе Python 3 относительно второй версии. Одно лишь разделение типа char на аналог wchar_t и byte в одной из следующих редакций стандарта приведет к коллапсу языка и потере совместимости с непомерным количеством уже написанного кода на С/С++. Точнее, всего, на чем ты сейчас работаешь.

Веселые перекодировки

Итак, исходная проблема осталась нерешенной. У нас по-прежнему есть однобайтовые кодировки, как UTF-8, так и старые и недобрые однобайтовые кодировки вроде кодировки Windows 1251. С другой стороны, мы задаем строковые константы широкими строками и обрабатываем текст через wchar_t — «широкие» символы.

Здесь нам на помощь придет механизм перекодировок. Ведь, зная кодировку набора байтов, мы всегда сможем преобразовать его в набор символов wchar_t и обратно. Не спеши только самостоятельно создавать свою библиотеку перекодировки, я понимаю, что коды символов любой кодировки сейчас можно найти за минуту, как и всю таблицу кодов Юникода последней редакции. Однако библиотек перекодировки достаточно и без этого. Есть кросс-платформенная библиотека libiconv, под лицензией LGPL, самая популярная на сегодняшний день для кросс-платформенной разработки. Перекодировка сводится к нескольким инструкциям:

Соответственно, сначала создание обработчика перекодировки из одной кодировки в другую, затем сама операция перекодировки одного набора байтов в другой (даже если один из наборов байтов на самом деле байты массива wchar_t), после чего обязательное закрытие созданного обработчика перекодировки. Есть также и более амбициозная библиотека ICU, которая предоставляет как C++ интерфейс для работы с перекодировкой, так и специальный тип icu::UnicodeString для хранения непосредственно текста в представлении Юникода. Библиотека ICU также является кросс-платформенной, и вариантов ее использования предоставляется на порядок больше. Приятно, что библиотека сама заботится о создании, кешировании и применении обработчиков для перекодировки, если использовать C++ API библиотеки.

Например, чтобы создать строку в Юникоде, предлагается использовать обычный конструктор класса icu::UnicodeString:

Таким образом, предлагается полностью отказаться от типа wchar_t. Проблема, однако, в том, что внутреннее представление Юникода для такой строки установлено в два байта, что влечет за собой проблему в случае, когда код за эти два байта выходит. Кроме того, интерфейс icu::UnicodeString полностью несовместим со стандартным wstring, однако использование ICU — хороший вариант для С++ разработчика.

Кроме того, есть пара стандартных функций mbstowcs и wcstombs. В общем и целом при правильно заданной локали они, соответственно, преобразуют (мульти-) байтовую строку в «широкую» и наоборот. Расшифровываются сокращения mbs и wcs как Multi-Byte String и Wide Character String соответственно. Кстати, большинство привычных разработчику на языке си функций работы со строками дублируются именно функциями, в которых в названии str заменено на wcs, например wcslen вместо strlen или wcscpy вместо strcpy.

Нельзя не вспомнить и о Windows-разработке. Счастливых обладателей WinAPI ждет очередная пара функций с кучей параметров: WideCharToMultiByte и MultiByteToWideChar. Делают эти функции ровно то, что говорят их названия. Указываем кодировку, параметры входного и выходного массива и флаги и получаем результат. Несмотря на то что функции эти внешне страшненькие, работу свою делают быстро и эффективно. Правда, не всегда точно: могут попытаться преобразовать символ в похожий, поэтому осторожнее с флагами, которые передаются вторым параметром в функцию, лучше указать WC_NO_BEST_FIT_CHARS.

Разумеется, этот код не переносим на любую платформу, кроме Windows, поэтому крайне рекомендую пользоваться кросс-платформенными библиотеками ICU4C или libiconv.

Наиболее популярная библиотека — именно libiconv, однако в ней используются исключительно параметры char*. Это не должно пугать, в любом случае массив чисел любой битности — это всего лишь набор байтов. Следует, однако, помнить про направление двубайтовых и более чисел. То есть в каком порядке в байтовом массиве представлены байты — компоненты числа. Различают Big-endian и Little-endian соответственно. Общепринятый порядок представления чисел в подавляющем большинстве машин — Little-endian: сначала идет младший байт, а в конце старший байт числа. Big-endian знаком тем, кто работает с протоколами передачи данных по сети, где числа принято передавать начиная со старшего байта (часто содержащего служебную информацию) и кончая младшим. Следует быть аккуратным и помнить, что UTF-16, UTF-16BE и UTF-16LE — не одно и то же.

Класс текста

Давай теперь аккумулируем полученные знания и решим исходную задачу: нам нужно создать сущность, по сути класс, инициализируемый строкой, либо «широкой», либо байтовой, с указанием кодировки, и предоставляющий интерфейс привычного контейнера строки std::string, с возможностью обращения к элементам-символам, изменяя их, удаляя, преобразуя экземпляр текста в строке как «широкой», так и байтовой с указанием кодировки. В общем, нам нужно значительно упростить работу с Юникодом, с одной стороны, и получить совместимость с прежде написанным кодом, с другой стороны.

Класс текста, таким образом, получит следующие конструкторы:

Стоит перегрузить также от std::string и std::wstring вариантов, а также от итераторов начала и конца контейнера-источника.

Доступ к элементу, очевидно, должен быть открыт, но в качестве результата нельзя использовать байтовый char или платформозависимый wchar_t, мы должны использовать абстракцию над целочисленным кодом в таблице Юникода: symbol.

С другой стороны, за пределами класса text никому не нужен наш `std::basic_string `, назовем его `unicode_string`. Все библиотеки любят работать с `std::string` и `std::wstring` или `char const*« и `wchar_t const*`. Таким образом, лучше всего кешировать как входящий std::string или std::wstring, так и результат перекодировки текста в кодировку байт-строки. Мало того, часто наш класс text понадобится лишь как временное хранилище для путешествующей строки, например байтовой в UTF-8 из базы данных в JSON-строку, то есть перекодирование в unicode_string нам понадобится лишь по требованию обратиться к элементам — символам текста. Текст и его внутреннее представление — это тот класс, который должен быть оптимизирован по максимуму, так как предполагает интенсивное использование, а также не допускать перекодировок без причины и до первого требования. Пользователь API класса text должен явно указать, что хочет преобразовать текст в байтовую строку в определенной кодировке либо получить специфичную для системы «широкую» строку:

Нужно не забыть также и о получении char const* и wchar_t const*, что несложно делается, учитывая то, что std::string и std::wstring кешируются полями класса text.

Реализация сводится к вызову `c_str()« у результатов byte_string и wide_string соответственно.

Можно считать кодировкой по умолчанию для байтовых строк UTF-8, это гораздо лучше, чем пытаться работать с системной кодировкой по умолчанию, так код в зависимости от системы будет работать по-разному. Введя ряд дополнительных перегрузок без указания кодировки при работе с байтовыми строками, мы также получаем возможность переопределить оператор присвоения:

Нужно также не забыть о перегрузке операторов + и +=, но в целом остальные операции можно уже сводить к аргументу и результату типа text, универсальному значению, предоставляющему текст вне зависимости от кодировки.

Разумеется, Академия C++ не была бы академией, если бы я не предложил тебе теперь реализовать класс текста самостоятельно. Попробуй создать класс text на основе материала этой статьи. Реализация должна удовлетворять двум простым свойствам:

Разумеется, в реализации не обойтись без класса `copy_on_write` из предыдущих статей. Как обычно, на всякий случай напоминаю его упрощенный вид:

Что мы получаем

Реализовав класс text, мы получим абстракцию от множества кодировок, все, что нам потребуется, — одна перегрузка от класса text. Например, так:

Нам больше не нужно множество перегрузок от `std::string` и `std::wstring`, не нужно будет переходить на поддержку «широких» строк, достаточно заменить в API ссылки на строки на text, и получаем Юникод автоматом. Вдобавок мы получаем отличное кросс-платформенное поведение, вне зависимости от того, какую библиотеку мы выбрали в качестве движка перекодировки, — ICU4C или libiconv, ввиду того, что внутреннее представление у нас всегда UTF-32 при распаковке символов и мы нигде не завязаны на платформозависимый wchar_t.

Итого: у нас есть совместимость либо взаимоконвертация со стандартными типами, а значит, и упрощение поддержки Юникода на стороне кода, написанного на С++. Ведь если мы пишем высокоуровневую логику на C++, меньше всего нам хочется получить проблемы при использовании wchar_t символов и кучи однообразного кода при обработке и перекодировке текста.

При том что сама перекодировка уже реализована в тех же ICU4C и libiconv, алгоритм для внутренней работы класса text довольно прост. Дерзай, и, может, уже завтра именно твоя библиотека работы с текстом будет использоваться повсюду в качестве высокоуровневой абстракции при обработке любых текстовых данных, от простого JSON с клиента до сложных текстовых структур со стороны различных баз данных.

Кодировка utf 8 с bom что это. aa5d92a28f1e7719cf1e453ebc32758f. Кодировка utf 8 с bom что это фото. Кодировка utf 8 с bom что это-aa5d92a28f1e7719cf1e453ebc32758f. картинка Кодировка utf 8 с bom что это. картинка aa5d92a28f1e7719cf1e453ebc32758f. Reg.ru: домены и хостинг

Впервые опубликовано в журнале Хакер #191.
Автор: Владимир Qualab Керимов, ведущий С++ разработчик компании Parallels

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *