Ромбик с вопросительным знаком в конце текста

ромбик с вопросиком

Иногда нам требуется вывести не весь текст поста или комментария, а только его начало, и дать ссылку на продолжение «читать далее». Но стоит нам обрезать текст, как в конце его появляется (иногда) ромбик со знаком вопроса внутри (или рамка с мелкими циферками «1001» — в зависимости от браузера). Предлагаю разобраться, почему такое происходит, и устранить проблему.

Очень популярной кодировкой текста в современном Вебе является «UTF-8». Например, именно её использует WordPress. Кодировка эта мультибайтная, благодаря чему в ней закодированы сотни алфавитов и разнообразные графические символы.

Суть вопроса

Но многие функции PHP писались изначально под однобайтные кодировки. Если при использовании таких функций (например, substr()) указать, что вам нужно взять первые 100 символов строки, то функция возьмёт первые 100 байт. Однако, 1 байт в кодировке «utf-8» занимают далеко не все символы. К примеру, английские буквы и знаки препинания занимают 1 байт, а вот русские буквы занимают 2 байта.

Не все функции учитывают такую особенность кодировки «utf-8», потому случается, что при обрезке строки последний символ «режется пополам». В итоге в конце строки мы имеем символ с номером, отображение которого браузером не предусмотрено — он и будет показан как вопросик в ромбе или какая-то другая непонятная неожиданная символика.

substr работает некорректно

Бывают и другие странности. Например, функцией strlen() вы захотите определить длину строки. Если строка, к примеру, «PHP!» — проблем никаких, результат верный: 4. Но если строка: «Ура!» — результат будет: 7. Если разобраться, в этом нет ничего странного, поскольку кириллические символы занимают по 2 байта, а восклицательный знак — 1 байт. И, если мы захотим усечь строку «Ура!» до 3-х символов функцией substr(), то вместо ожидаемого «Ура» получим «У» и половинку буквы «р» в виде вопросика в ромбе.

Решение

Для устаревших функций работы со строками существуют мультибайтные аналоги. Например, функции strlen() соответствует функция mb_strlen(), для функции substr() есть мультибайтный аналог mb_substr(). Синтаксис почти идентичен, за тем лишь исключением, что вы можете (не обязательно) одним из аргументов указывать кодировку, с которой работаете. Пример:

mb_strlen( 'Ура!', 'utf-8' )

Вернёт корректный результат: 4. Внимание! Если явно не указать кодировку, будет использована серверная кодировка «по умолчанию». А она может отличаться от кодировки, в которой вы работаете над сайтом.

Указывать кодировку явно не всегда удобно. Например, когда требуется взять часть строки с 5 символа до конца, удобней воспользоваться такой конструкцией:

mb_substr( 'разрезаемая строка', 5 )

Здесь я не указал, сколько символов мне нужно, потому функция вернёт весь остаток строки. Но если нужно указать кодировку, код становится сложней:

mb_substr( 'разрезаемая строка'.'1', 5, -1, 'utf-8' )

Тут уже надо явно задавать, сколько нужно символов в результате, чтобы следующим аргументом указать кодировку (нельзя один аргумент пропустить, а следующий указать). Чтобы избежать ещё большего усложнения кода (использования функции mb_strlen() для определения длины строки) я прибегнул к хитрости — добавил к строке произвольный символ '1' и аргументом «-1» указал, что мне нужна вся строка с 5-го до последнего символа (1 с конца).

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

mb_internal_encoding( 'utf-8' )

Один раз указали «UTF-8» — и в дальнейшем в своих функциях кодировку можно не указывать, если в них вы планируете работать со строками, кодированными в «UTF-8». Функцию mb_internal_encoding() я обычно прописываю в файле конфигурации проекта. Т.е. в том файле, который гарантированно будет подключен в первую очередь, до обработки кодов различных скриптов моего проекта.

Замечание

В официальных источника сказано, что расширение mbstring не входит в список расширений, устанавливаемых по умолчанию. А вот расширение iconv по умолчанию включено. При написании скриптов для себя, вам достаточно просто проверить, включено ли на вашем хостинге mbstring (и можно даже включить, если выключено). Но, при написании скриптов в продакшн, один из ста клиентов создаст вам проблемы. Чтобы этого избежать, пользуйтесь аналогичными функциями расширения iconv:

  • iconv_strlen — Возвращает количество символов в строке
  • iconv_strpos — Возвращает позицию первого вхождения подстроки
  • iconv_strrpos — Возвращает позицию последнего вхождения подстроки
  • iconv_substr — Получение части строки
  • iconv — Преобразование строки в требуемую кодировку
  • и т.д.

За подсказку выражаю благодарность x64 (aka andi).

Запись опубликована в рубрике Web-мастеринг с метками . Короткая ссылка для добавления в закладки: Ромбик с вопросительным знаком в конце текста.

11 Responses

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

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

Иногда ваш комментарий может не отобразиться сразу после публикации - будто пропал. Не волнуйтесь, он не пропадёт и появится потом, после моего одобрения.