Убедитесь, что строка закодирована в формате UTF-8


В своем приложении я читаю csv-файл и показываю содержимое пользователю. Но есть проблема с кодировкой.

У меня есть два файла csv пример1.csv и пример2.csv. Я открыл оба в notepad++, в котором показана кодировка ANSI, например, 1, и UTF-8 без спецификации, например, 2.

Во-первых, я попытался mb_detect_encoding-кодирование функция для определения кодировки, но в обоих случаях она показывает мне UTF-8, что неверно.

Во-вторых, я пытаюсь преобразуйте содержимое файла в UTF-8 с помощью код utf8_encode. Это работает для файла ANSI. Но для файла UTF-8 без спецификации кажется, что он был закодирован обратно в ANSI. Он отображает Ã вместо немецкого β. То же самое для других специальных символов.

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


Вот как я использую кодирование mb_detect_encoding функция:

$file_content = file_get_contents($_FILES['file']['tmp_name']);

die(var_dump( mb_detect_encoding($file_content))); 

И он печатает UTF-8 для обоих примеров.

Author: Artjom Zabelin, 2013-03-02

2 answers

В: еще одна неудобная правда

Невозможно определить кодировку неизвестного текста со 100% точностью и/или уверенностью.

На практике будут случаи по всему спектру возможных результатов: вы можете быть уверены, что многоязычный текст в UTF-8 будет правильно обнаружен как таковой, в то время как совершенно невозможно определить, какая из кодировок семейства ISO-8859 соответствует некоторому тексту - и если вы не готовы это сделать статистический анализ, даже невозможно сделать обоснованное предположение!

С чем нам приходится работать?

С этим покончено, давайте посмотрим, что вы можете сделать. Прежде всего, если вы не используете в бою собственные инструменты, вы ограничены тем, что mb_detect_encoding может сделать для вас. К сожалению, это не так уж много. Документация дочерней функции mb_detect_order состояния:

Mbstring в настоящее время реализует следующее определение кодировки фильтры. Если существует недопустимая последовательность байтов для следующих кодировок, обнаружение кодировки завершится ошибкой.

UTF-8, UTF-7, ASCII, EUC-JP, SJIS, eucJP-выигрыш, SJIS-выигрыш, JIS, ISO-2022-JP.

Для ISO-8859-X mbstring всегда определяет как ISO-8859-X.

Для UTF-16, UTF-32, UCS2 и UCS4 обнаружение кодировки всегда будет неудачным.

Таким образом, если не учитывать японские кодировки, у вас в основном есть возможность различать UTF-8, UTF-7 и ASCII. Вы не можете определить ISO-8859-X, потому что любой текст будет "распознан" как любой из этих кодировок, если вы учтете это (т.Е. У вас будет 100% ложноположительный результат - не очень хорошо), а группа, включающая UTF-16, просто не поддерживается.

К сожалению, плохие новости на этом не заканчиваются. Порядок кодировок тоже имеет значение! Поскольку текст, закодированный в UTF-7 или ASCII, также является допустимым UTF-8, размещая UTF-8 в начале список кандидатов гарантирует, что это единственный результат, который вы когда-либо получите, поэтому его следует избегать любой ценой.

Поскольку порядок обнаружения по умолчанию зависит от настройки php.ini , вам определенно не следует полагаться на это и переходить в известное состояние, установив свой собственный порядок обнаружения:

mb_detect_order('ASCII, UTF-8'); // I left UTF-7 out, but who cares?

Таким образом, вы можете, по крайней мере, сказать, является ли ваш текст ASCII или UTF-8, верно? Ну, нет. Нет, если только вы специально не попросите, чтобы, когда вы говорите "UTF-8", вы действительно имели в виду это:

$valid_utf8 = "\xC2\xA2";
$invalid_utf8 = "\xC2\x00";

mb_detect_order('UTF-8');
echo mb_detect_encoding($valid_utf8);   // "utf-8": correct
echo mb_detect_encoding($invalid_utf8); // "utf-8": WTF?!?!?!

Проблема выше заключается в том, что если вы не передадите true для параметра $strict, обнаружение UTF-8 будет... немного чересчур оптимистично.

Ну, а что вы на самом деле можете сделать с этой штукой?

Это настолько хорошо, насколько это возможно - правильный способ обнаружения кодировок (здесь едва удается использовать множественное число):

$valid_utf8 = "\xC2\xA2";
$invalid_utf8 = "\xC2\x00";
$ascii = "hello world";

mb_detect_order('ASCII, UTF-8');
echo mb_detect_encoding($valid_utf8, mb_detect_order(), true);   // OK: "utf-8"
echo mb_detect_encoding($invalid_utf8, mb_detect_order(), true); // OK: false
echo mb_detect_encoding($ascii, mb_detect_order(), true);        // OK: "ascii"

Что можно сделать с текстом, который не является допустимым UTF-8?

Если только у вас нет внеполосной информации об этом тексте, к сожалению ничего.

Хорошо, это не совсем так. Есть несколько вещей, которые вы можете сделать на практике:

  1. Посмотрите, есть ли спецификация в начале текста. Вероятно, их не будет, и даже если они есть, математически вы можете ошибочно принять однобайтовую кодировку за Юникод, но попробовать стоит.
  2. Посмотрите, не является ли это разновидностью UTF-16. Если подавляющее большинство четных байтов имеют одинаковое значение, то вы, скорее всего, смотрите на файл UTF-16. Если это случается, что для большинства байтов с нечетными номерами вы, скорее всего, смотрите на UTF-16 BE. К сожалению, в обоих случаях вы никогда не можете быть уверены.
  3. Предположим, что текст соответствует стандарту ISO-8859-X, и проведите статистический анализ на основе известных свойств сценария, соответствующего этой кодировке, чтобы увидеть, близок ли результат к ожидаемому. Если это достаточно близко для некоторых кодировок в этом классе и далеко для других, вы можете сделать обоснованное предположение.
 9
Author: Jon, 2013-03-02 20:27:51

Для проверки utf8 сделайте что-то вроде этого

if (mb_check_encoding(file_get_contents($file), 'UTF-8')) {
    // yup, all UTF-8
}
 -1
Author: Vineet1982, 2013-03-02 17:59:54