Strlen() и UTF-8

Предполагая кодировку UTF-8 и strlen() в PHP, возможно ли, что эта строка имеет длину 4?

Мне интересно узнать о strlen(), а не о других функциях

Это строка: $1�2

Я тестировал его на своем собственном компьютере, и я проверил кодировку UTF-8, и ответ, который я получаю, равен 6.

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

PS: Этот вопрос и ответ (4) исходят из ложного теста для ZCE, который я купил на Ebay.

PPS: Пожалуйста, бросьте мне кость и проголосуйте за нее. Я сделал домашнее задание. Заранее благодарю всех ответов и голосов.

Ответ 1

Строка, которую вы отправили, имеет длину шесть символов: $1�2 (знак доллара, цифра один, строчный регистр я с диарезисом, знак перевернутого вопроса, одна половина, цифра два)

Если strlen() вызывается с представлением UTF-8 этой строки, вы получите результат из девяти (вероятно, хотя есть несколько представлений с разной длиной).

Однако, если бы мы сохранили эту строку как ISO 8859-1 или CP1252, у нас была бы шестибайтная длинная последовательность, которая была бы законна как UTF-8. Интерпретация этих 6 байтов, как UTF-8, приведет к 4 символам: $1 2 (знак доллара, цифра один, символ замены Unicode, цифра 2). То есть кодировка UTF-8 одиночного символа "" идентична кодировке ISO-8859-1 трех символов "�".

Символ замены часто вводится, когда декодер UTF-8 считывает данные, которые не соответствуют данным UTF-8.

Похоже, что исходная строка обрабатывалась несколькими уровнями неправильной интерпретации; с использованием декодера UTF-8 для данных, отличных от UTF-8 (с получением $1 2), а затем с помощью того, что вы использовали для анализа этих данных (с получением $1 ½½).

Ответ 2

как насчет использования mb_strlen()?

http://lt.php.net/manual/en/function.mb-strlen.php

Но если вам нужно использовать strlen, можно настроить свой веб-сервер, установив директиву mbstring.func_overload на 2, поэтому он автоматически заменит использование strlen в mb_strlen в ваших сценариях.

Ответ 3

необходимо использовать функцию многобайтовой строки mb_strlen(), например:

mb_strlen($string, 'UTF-8');

Ответ 4

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

Последовательность � получается при кодировании символа символа U + FFFD ( ) в UTF-8 и интерпретации результата в latin1. Этот символ используется в качестве замены байтовых последовательностей, которые не кодируют какого-либо символа при чтении текста из файла, например. Вероятно, произошло следующее:

Исходный вопрос, сохраненный в текстовом файле latin1, имел: $1¢2 (вы можете заменить ¢ любым символом, отличным от ASCII)

Файл был прочитан программой, использующей UTF-8. Поскольку байт, соответствующий ¢, не может быть интерпретирован, программа заменила его и прочитала текст $1�2. Затем этот текст был выписан с использованием UTF-8, в результате получилось $1\xEF\xBF\xBD2 в файле.

Затем появляется какая-то третья программа, которая читает файл в latin1 и показывает $1�2.

Ответ 5

Нет.

Я буду использовать доказательство от противного.

strlen подсчитывает байты, поэтому с strlen из 4 в этой строке должно быть ровно 4 байта.

Для кодирования UTF8 требуется не менее 1 байт на символ.

Мы установили, что:

  • есть 4 байта
  • символ представлен не менее чем 1 байт

... но у нас есть 6 символов.... что противоречие. Итак, нет.

Однако не совсем понятно, какой символ задает программное обеспечение для показа (например, веб-браузер), использующее intepret строку. Он может использовать какую-то необычную схему кодирования, где символ может быть представлен менее чем 8 бит. Если это так, то 4 байта могут отображаться как 6 символов. Таким образом, строка может быть utf8, но браузер может решить интерпретировать ее как, скажем, с 5-битным набором символов.

Ответ 6

Многие символы UTF-8 принимают несколько байтов вместо одного. Это как UTF-8 (так как вы можете иметь так много символов в одном наборе).

Попробуйте mb_strlen().