Unicode

Данные программы хранятся в памяти компьютера (оперативной или постоянной) в виде последовательности нулей и единиц. На этом уровне нет разницы между строками, числами или булевыми значениями, в памяти все выглядит одинаково. Разница появляется только в результате интерпретации. Программа знает, что внутри некоторой переменной хранится строка, поэтому она берет нули и единички и пропускает их сквозь кодовую таблицу, в которой указано, какому числу соответствует какая буква. В результате программист видит строку.

В самом начале была ровно одна кодировка — ASCII, основанная на английском алфавите. В этой кодировке одному символу соответствует 7 байт, всего в ней закодировано 128 символов. 95 из них печатные, они включают в себя буквы алфавита в верхнем и нижнем регистре, цифры и знаки препинания, а также 33 непечатных символа или так называемых управляющих кодов. Большинство из них сейчас не актуальны, но некоторые, например, перевод строки \n по прежнему используются. Например, символ i в нижнем регистре соответствует двоичному числу 1101001, что соответствует числу 105 в десячтичной системе счисления.

Поначалу все было хорошо, но с распространением компьютеров возникла потребность в других алфавитах. Каждая страна решала данную проблему созданием собственной кодировки, большинство из которых совместимы с ASCII. То есть первые 128 номеров полностью соответствовали ASCII, а вот остальные 127 заполнялись локальным алфавитом. 128 + 127 = 256, а это 2 в 8 степени. Эти кодировки были однобайтовыми (для хранения одного символа требовался один байт). Внезапно открылись врата ада. Попытка открыть в редакторе файл в другой кодировке, приводила к появлению крякозябр: Øèðîêàÿ ýëåêòðèôèêàöèÿ þæíûõ ãóáåðíèé äàñò ìîùíûé òîë÷îê ïîäú¸ìó ñåëüñêîãî õîçÿéñòâà. Возникают они потому, что один и тот же код в разных кодировках соответствует совершенно разным символам, за исключением первых 128. Поэтому текст, использующий английские буквы всегда читался, а в остальном как повезет. Ситуация усугублялась тем, что даже в рамках одного алфавита создавалось множество разных кодировок, например: Windows-1252, KOI8-R, CP 866, ISO 8859-5.

В языках программирования на тот момент все функции для работы со строками создавались из расчета, что один символ — это один байт. По крайней мере, это свойство было общим для всех кодировок.

Разные кодировки стали причиной постоянных проблем при взаимодействии людей и программ. Особенно остро эта проблема проявилась с развитием интернета. Такая ситуация не могла продолжаться бесконечно, и в конце концов был создан стандарт Unicode. На данный момент он содержит более 100 тысяч символов и включает в себя все существующие (и даже мертвые) языки. Unicode не является кодировкой и ничего не говорит о том, как должны храниться символы в памяти, он лишь определяет связь между символом и некоторым числом. Конкретный способ кодирования юникода определяется соответствующими кодировками, среди которых utf-8, utf-16 и некоторые другие. В этих кодировках для хранения одного символа уже недостаточно одного байта, они используют больше. utf-8 ведет себя хитрее: для символов английского алфавита (и некоторых других) используется один байт, для других алфавитов - 2.

После многих лет популяризации юникода свершилось чудо, и сейчас подавляющее большинство программного обеспечения использует utf-8. Этот процесс был болезненный и по-разному отразился на языках программирования. Например, в PHP стандартные функции по прежнему не поддерживают многобатовые кодировки.

<?php

echo strlen('Привет!'); // 13

Языки разделились на два лагеря. Некоторые встроили поддержку в уже существующие функции и переход на utf-8 никак не отразился на процессе программирования. Среди них Java, Ruby, JavaScript. А вот PHP пошел своим, особенным путем. Для работы с многобатовыми кодировками в язык добавили отдельную стандартную библиотеку, которая по большей части повторяет функции для работы со строками, с той лишь разницой, что каждая функция имеет префикс mb_ (multybite).

<?php

echo mb_strlen('Привет!'); // 7

А вот достойной альтернативы взятию конкретного символа в строке по индексу не существует. Такую задачу придется выполнять используя mb_substr

<?php

$str = 'Привет';
$symbol = mb_substr($str, 2, 1); // и

Задание

Реализуйте функцию invertCase, которая инвертирует регистр каждого символа в переданной строке

<?php

$str = 'ПрИвЕт!';
invertCase($str); // пРиВеТ!

Упражнение доступно только авторизованным пользователям.

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