Страницы

Поиск по вопросам

воскресенье, 9 февраля 2020 г.

Посимвольный вывод слов

#php #utf_8 #unicode


Здравствуйте!

Есть такая конструкция, которая выведет первую букву переменной $str, которая будет
равна 't':

mb_internal_encoding("UTF-8");
$str = 'test';
print_r($str[0]);   //    выведет 't'


Но почему это не работает с русскими словами?

mb_internal_encoding("UTF-8");
$str = 'тест';
print_r($str[0]);   //    выведет '�', вместо 'т'


Кодировка вроде выставлена, но почему в выводе  знак вопроса?

Подскажите, пожалуйста, как решить?

Спасибо!
    


Ответы

Ответ 1



Всё дело в том, что в кодировке UTF-8 единичный символ может занимать разное количество байт (от 1 до 6 или даже больше). Английские буквы, цифры, некоторые знаки препинания занимают по одному байту, и их представление ничем не отличается, как если бы они были закодированы в ASCII. Для букв русского алфавита, букв европейских языков, которых нет английском (например, немецкая Ö), для арабского алфавита, нужно уже по два байта. Распространённые восточные иероглифы занимают уже по 3 байта каждый. А всеми любимые эмодзи кодируются последовательностями от 4 байтов. Итак, давайте рассмотрим байтовое представление ваших строк. test -> 74 65 73 74 тест -> D1 82 D0 B5 D1 81 D1 82 Слева показано то, как эти буквы видим мы, справа — их побайтовое представление в памяти компьютера, причём значения байтов записаны в 16-ричной системе счисления (чтобы не занять много места). Как видите, русское слово занимает в два раза больше памяти, хотя букв в нём столько же. Кроме того, обратите внимание, каждый байт в его кодированном варианте не меньше 8016. Теперь вернёмся к PHP. Строки в этом языке о кодировках ничего не знают, а просто хранят в себе только байты. И оператор индексирования тоже ничего про кодировки, буквы, символы не знает; он просто, будучи применённым к строке, возвращает байт с указанным номером. Поэтому, когда вы пытаетесь напечатать первый байт (с номером 0), в первом случае выводится байт со значением 7416, который на экране компьютера виден как маленькая латинская буква «t». А во втором случае на вывод подаётся байт со значением D116, представляющий собой огрызок русской буквы «т»; не зная, какой байт идёт дальше, устройство вывода (терминал или веб-обозреватель) просто рисует знак вопроса. Что же делать, как напечатать только первый символ из строки? В качестве решения можно применить функции из расширения php-mbstring. $letter = mb_substr($str, 0, 1); // вернёт первый code point из строки Но учтите, функция mb_substr оперирует понятием code point, а не graphical cluster. Какое же это имеет значение? Стандарт юникода позволяет составлять некоторые буквы из нескольких code points. К примеру, буква «ё» может оказаться комбинацией буквы «е» и умляута.

Ответ 2



Используйте mb_substr: mb_substr($string, $letter, 1, "utf-8"); //$string - строка //$letter - индекс нужной буквы //1 - сколько символов включая нужную нужно вернуть //"utf-8" - кодировка

Комментариев нет:

Отправить комментарий