Та же кодировка (UTF-8), но разная длина строки и содержимого (PHP)

У меня есть две строковые переменные - первая переменная задается вручную внутри кода ($date1="14 июня"), вторая анализируется с удаленной страницы с помощью cURL и phpQuery. Если мы напечатаем обе переменные, результат будет выглядеть одинаково, но длина и содержимое будут другими:

echo $date1; //output: 14 июня
echo $date2; //output: 14 июня
echo $date1[2]; //output is space - third symbol in string
echo $date2[2]; //output is � - it's a part of third symbol in string
echo strlen($date1); //output: 7
echo strlen($date2); //output: 12
echo mb_detect_encoding($date1) //output: UTF-8
echo mb_detect_encoding($date2) //output: UTF-8

Интересно, есть ли решение, как преобразовать $date2 в формат/кодировку $date1?

p.s. Существует ТАК тема про iconv(), но я не могу найти работающее решение.


person deeplay    schedule 16.06.2017    source источник
comment
strlen() возвращает 11 для текста, который вы разместили (я скопировал строку из вопроса).   -  person axiac    schedule 16.06.2017
comment
Там дополнительно есть невидимые символы. Показать echo bin2hex($s) для обоих.   -  person zerkms    schedule 16.06.2017
comment
Укажите способ воспроизвести проблему.   -  person axiac    schedule 16.06.2017
comment
Дамп переменных с выражением вроде var_dump(array_shift(unpack('H*', $dateX)));   -  person Ruslan Osmanov    schedule 16.06.2017
comment
@RuslanOsmanov, для даты1 - string(22) "313420d0b8d18ed0bdd18f" и для даты2: string(14) "3134204a756e65"   -  person deeplay    schedule 16.06.2017
comment
извините, ребята, я предоставил неправильный вывод, пожалуйста, найдите реальный вывод (как вы просили): для даты1 - 313420d0b8d18ed0bdd18f и для даты2: "3134c2a0d0b8d18ed0bdd18f"   -  person deeplay    schedule 16.06.2017
comment
Итак, вы не можете сравнить их и увидеть, что у последнего там лишние c2a0 байты, а у первого используется 20 в качестве пробела?   -  person zerkms    schedule 16.06.2017
comment
Итак, ваше решение состоит в том, чтобы вручную удалить этот лишний байт?   -  person deeplay    schedule 16.06.2017
comment
Это просто другой тип пространства. Вам решать, что с этим делать. fileformat.info/info/unicode/char/00a0/index.htm< /а>   -  person zerkms    schedule 16.06.2017
comment
снова понизьте голоса фей. Законный вопрос +1   -  person Robert Sinclair    schedule 04.08.2017


Ответы (1)


Итак, у вас есть 2 строки:

313420d0b8d18ed0bdd18f — в качестве пробела используется символ 0x20.

3134c2a0d0b8d18ed0bdd18f — в качестве пробела используется последовательность байтов 0xC2A0. (это неразрывный пробел Unicode).

Кроме этих пробелов, строки идентичны.

Чтобы заменить символы Юникода, похожие на пробелы, на обычный пробел, вы можете использовать следующее регулярное выражение:

preg_replace('~\p{Zs}~u', ' ', $str)

Использованная литература:

person zerkms    schedule 16.06.2017
comment
Есть ли какой-нибудь метод php для преобразования всех символов/последовательностей/символов, подобных этому? Для пробела - ок, я его заменю, а как насчет другого такого персонажа? - person deeplay; 16.06.2017
comment
Спасибо @zerkms! Теперь такие функции, как explode(' ',$date2), работают нормально. Но длина все равно другая, думаю это из-за кириллических символов. Есть ли способ преобразовать дату2, я думаю, что длина июня должна быть 4. - person deeplay; 16.06.2017
comment
@deeplay Используйте mb_strlen() для измерения длины многобайтовых строк. echo mb_strlen('июня', 'utf8'); // 4 - person zerkms; 16.06.2017
comment
Я знаю о mb функциях. Похоже, нет возможности конвертировать. Для меня странно, что обе строки в кодировке UTF-8, но с разным содержанием. Спасибо за помощь. - person deeplay; 16.06.2017
comment
@deeplay июня при кодировании в utf-8 составляет 8 байтов, поскольку все символы кириллицы имеют длину 2 байта. А strlen просто считает длину строки в байтах. Таким образом, невозможно сказать, что июня находится в utf8 и имеет длину, отличную от 8 байт. - person zerkms; 16.06.2017