PHP: Юникод
Данные программы хранятся в памяти компьютера в виде последовательности нулей и единиц. На этом уровне нет разницы между строками и числами. В памяти все выглядит одинаково. Разница появляется только в результате интерпретации.
Программа знает, что внутри некоторой переменной хранится строка, поэтому она берет нули и единички и пропускает их сквозь кодовую таблицу. В ней указано, какому числу соответствует какая буква. В результате программист видит строку. В этом уроке мы обсудим, как работают такие кодовые таблицы.
В самом начале была только ASCII — кодировка, основанная на английском алфавите.
В этой кодировке одному символу соответствует 7 бит, всего в ней закодировано 128 символов:
- 95 печатных символов, включая буквы алфавита в верхнем и нижнем регистрах, цифры и знаки препинания
- 33 непечатных символа (управляющих кода)
Большинство непечатных символов сейчас не актуальны, но некоторые по-прежнему используются — например, перевод строки \n.
Символы в ASCII можно перекодировать. Например, символ i в нижнем регистре соответствует:
- Числу
1101001в двоичной системе счисления - Числу
105в десятичной системе
Поначалу все было хорошо, но с распространением компьютеров возникла потребность в других алфавитах. Каждая страна решала данную проблему созданием собственной кодировки, большинство из которых совместимы с ASCII:
- Первые 128 символа полностью соответствовали ASCII
- Остальные 128 — заполнялись локальным алфавитом
В итоге в таких кодировках было 256 символов, а это 2 в 8 степени.
Эти кодировки были однобайтовыми — для хранения одного символа требовался один байт. Но внезапно возникла проблема: попытка открыть в редакторе файл в другой кодировке приводила к появлению «крякозябр»:
Øèðîêàÿ ýëåêòðèôèêàöèÿ þæíûõ ãóáåðíèé äàñò ìîùíûé òîë÷îê ïîäú¸ìó ñåëüñêîãî õîçÿéñòâà
Возникают они потому, что один и тот же код в разных кодировках соответствует совершенно разным символам, за исключением первых 128. Поэтому текст, использующий английские буквы всегда читался, а в остальном — как повезет. Ситуация усугублялась тем, что даже в рамках одного алфавита создавалось множество разных кодировок, например: Windows-1252, KOI8-R, CP 866, ISO 8859-5.
В языках программирования на тот момент все функции для работы со строками создавались из расчета, что один символ — это один байт. По крайней мере, это свойство было общим для всех кодировок.
Разные кодировки стали причиной постоянных проблем при взаимодействии людей и программ. Особенно остро эта проблема проявилась с развитием интернета. Такая ситуация не могла продолжаться бесконечно, и в конце концов был создан стандарт Юникод (Unicode).
Сейчас он содержит более 100 тысяч символов и включает в себя все существующие языки, даже мертвые. Стандарт Юникод не является кодировкой и ничего не говорит о том, как должны храниться символы в памяти, он лишь определяет связь между символом и некоторым числом.
Конкретный способ кодирования Юникода определяется соответствующими кодировками, среди которых есть UTF-8, UTF-16 и некоторые другие. В этих кодировках для хранения одного символа уже недостаточно одного байта, они используют больше. UTF-8 ведет себя хитрее: для символов английского алфавита и некоторых других используется один байт, для других алфавитов — два байта.
После многих лет популяризации Юникода свершилось чудо, и сейчас подавляющее большинство программного обеспечения использует UTF-8. Этот процесс был болезненный и по-разному отразился на языках программирования. Например, в PHP стандартные функции не поддерживают многобайтовые кодировки:
<?php
print_r(strlen('Привет!')); // => 13Языки разделились на два лагеря. Одни языки встроили поддержку в уже существующие функции — в итоге переход на UTF-8 никак не отразился на процессе программирования. Среди таких языков есть Java, Ruby, JavaScript.
А вот PHP пошел своим путем. Для работы с многобайтовыми кодировками в язык добавили отдельное расширение по работе с многобайтовыми строками. По большей части оно добавляет множество функций для работы со строками, с той лишь разницей, что каждая функция из них имеет префикс mb_ (multibyte):
<?php
print_r(mb_strlen('Привет!')); // => 7А вот достойной альтернативы взятию конкретного символа в строке по индексу не существует. Такую задачу нужно выполнять с помощью функции mb_substr():
<?php
$str = 'Привет';
$symbol = mb_substr($str, 2, 1); // иЗадание
Выведите на экран длину строки Привет! двумя способами: сначала с помощью функции strlen(), затем — mb_strlen(). Каждое значение должно быть на своей строке.
Так вы своими глазами увидите разницу между количеством байтов и количеством символов в юникод-строке.
Полезное
PHP: Юникод
Данные программы хранятся в памяти компьютера в виде последовательности нулей и единиц. На этом уровне нет разницы между строками и числами. В памяти все выглядит одинаково. Разница появляется только в результате интерпретации.
Программа знает, что внутри некоторой переменной хранится строка, поэтому она берет нули и единички и пропускает их сквозь кодовую таблицу. В ней указано, какому числу соответствует какая буква. В результате программист видит строку. В этом уроке мы обсудим, как работают такие кодовые таблицы.
В самом начале была только ASCII — кодировка, основанная на английском алфавите.
В этой кодировке одному символу соответствует 7 бит, всего в ней закодировано 128 символов:
- 95 печатных символов, включая буквы алфавита в верхнем и нижнем регистрах, цифры и знаки препинания
- 33 непечатных символа (управляющих кода)
Большинство непечатных символов сейчас не актуальны, но некоторые по-прежнему используются — например, перевод строки \n.
Символы в ASCII можно перекодировать. Например, символ i в нижнем регистре соответствует:
- Числу
1101001в двоичной системе счисления - Числу
105в десятичной системе
Поначалу все было хорошо, но с распространением компьютеров возникла потребность в других алфавитах. Каждая страна решала данную проблему созданием собственной кодировки, большинство из которых совместимы с ASCII:
- Первые 128 символа полностью соответствовали ASCII
- Остальные 128 — заполнялись локальным алфавитом
В итоге в таких кодировках было 256 символов, а это 2 в 8 степени.
Эти кодировки были однобайтовыми — для хранения одного символа требовался один байт. Но внезапно возникла проблема: попытка открыть в редакторе файл в другой кодировке приводила к появлению «крякозябр»:
Øèðîêàÿ ýëåêòðèôèêàöèÿ þæíûõ ãóáåðíèé äàñò ìîùíûé òîë÷îê ïîäú¸ìó ñåëüñêîãî õîçÿéñòâà
Возникают они потому, что один и тот же код в разных кодировках соответствует совершенно разным символам, за исключением первых 128. Поэтому текст, использующий английские буквы всегда читался, а в остальном — как повезет. Ситуация усугублялась тем, что даже в рамках одного алфавита создавалось множество разных кодировок, например: Windows-1252, KOI8-R, CP 866, ISO 8859-5.
В языках программирования на тот момент все функции для работы со строками создавались из расчета, что один символ — это один байт. По крайней мере, это свойство было общим для всех кодировок.
Разные кодировки стали причиной постоянных проблем при взаимодействии людей и программ. Особенно остро эта проблема проявилась с развитием интернета. Такая ситуация не могла продолжаться бесконечно, и в конце концов был создан стандарт Юникод (Unicode).
Сейчас он содержит более 100 тысяч символов и включает в себя все существующие языки, даже мертвые. Стандарт Юникод не является кодировкой и ничего не говорит о том, как должны храниться символы в памяти, он лишь определяет связь между символом и некоторым числом.
Конкретный способ кодирования Юникода определяется соответствующими кодировками, среди которых есть UTF-8, UTF-16 и некоторые другие. В этих кодировках для хранения одного символа уже недостаточно одного байта, они используют больше. UTF-8 ведет себя хитрее: для символов английского алфавита и некоторых других используется один байт, для других алфавитов — два байта.
После многих лет популяризации Юникода свершилось чудо, и сейчас подавляющее большинство программного обеспечения использует UTF-8. Этот процесс был болезненный и по-разному отразился на языках программирования. Например, в PHP стандартные функции не поддерживают многобайтовые кодировки:
<?php
print_r(strlen('Привет!')); // => 13Языки разделились на два лагеря. Одни языки встроили поддержку в уже существующие функции — в итоге переход на UTF-8 никак не отразился на процессе программирования. Среди таких языков есть Java, Ruby, JavaScript.
А вот PHP пошел своим путем. Для работы с многобайтовыми кодировками в язык добавили отдельное расширение по работе с многобайтовыми строками. По большей части оно добавляет множество функций для работы со строками, с той лишь разницей, что каждая функция из них имеет префикс mb_ (multibyte):
<?php
print_r(mb_strlen('Привет!')); // => 7А вот достойной альтернативы взятию конкретного символа в строке по индексу не существует. Такую задачу нужно выполнять с помощью функции mb_substr():
<?php
$str = 'Привет';
$symbol = mb_substr($str, 2, 1); // иЗадание
Выведите на экран длину строки Привет! двумя способами: сначала с помощью функции strlen(), затем — mb_strlen(). Каждое значение должно быть на своей строке.
Так вы своими глазами увидите разницу между количеством байтов и количеством символов в юникод-строке.
Полезное
Ваше упражнение проверяется по этим тестам
<?php
namespace HexletBasics\AdvancedStrings\Unicode;
use HexletBasics\Exercise\TestCase;
class SolutionTest extends TestCase
{
public function test()
{
$expected = "13\n7\n";
$this->assertOutput($expected);
}
}Решение учителя откроется через:
20:00
