Странное поведение mb_detect_order () в PHP

Я хотел бы обнаружить кодирование некоторого текста (использующий PHP). С этой целью я использую mb_detect_encoding () функция.

Проблема состоит в том, что функция возвращает различные результаты, если я изменяю порядок возможной кодировки с mb_detect_order () функция.

Рассмотрите следующий пример

$html = <<< STR
ちょっとのアクセスで落ちてしまったり、サーバー障害が多いレンタルサーバーを選ぶとあなたのビジネス等にかなりの影響がでてしまう可能性があります。特に商売をされている個人の方、法人の方は気をつけるようにしてください
STR;
mb_detect_order(array('UTF-8','EUC-JP', 'SJIS', 'eucJP-win', 'SJIS-win', 'JIS', 'ISO-2022-JP','ISO-8859-1','ISO-8859-2'));
$originalEncoding = mb_detect_encoding($str);
die($originalEncoding); // $originalEncoding = 'UTF-8'

Однако при изменении порядка кодировки в mb_detect_order (), результаты будут отличаться:

mb_detect_order(array('EUC-JP','UTF-8', 'SJIS', 'eucJP-win', 'SJIS-win', 'JIS', 'ISO-2022-JP','ISO-8859-1','ISO-8859-2'));        
die($originalEncoding); // $originalEncoding = 'EUC-JP'



Таким образом, мои вопросы:
Почему это происходит?
Существует ли путь в PHP к правильно, и однозначно обнаружьте кодирование текста?

7
задан Termos 21 May 2010 в 10:24
поделиться

4 ответа

Вот чего я ожидал.

Алгоритм обнаружения, вероятно, просто продолжает пытаться по порядку кодировки, указанные в mb_detect_order , а затем возвращает первую, при которой байтовый поток будет действителен.

Для чего-то более интеллектуального требуются статистические методы (я думаю, что машинное обучение широко используется).

РЕДАКТИРОВАТЬ: см., Например, эта статья для более интеллектуальных методов.

Из-за своей важности автоматическое определение кодировки уже реализовано в основных интернет-приложениях, таких как Mozilla или Internet Explorer. Они очень точные и быстрые, но при их реализации в каждом конкретном случае применяются многие знания, специфичные для предметной области. В отличие от их методов, мы стремились к простому алгоритму, который можно было бы единообразно применять к любой кодировке, и алгоритм основан на хорошо зарекомендовавших себя стандартных методах машинного обучения. Мы также изучили взаимосвязь между языком и определением кодировки и сравнили алгоритмы на основе байтов и алгоритмы на основе символов. Мы использовали Naive Bayes (NB) и машину опорных векторов (SVM).

5
ответ дан 6 December 2019 в 19:33
поделиться

mb_detect_encoding смотрит на первую запись charset в вашей mb_detect_order() и затем циклически просматривает ваш входной $html, сопоставляя символ за символом, попадает ли этот символ в допустимый набор символов для charset. Если все символы совпадают, то возвращается true; если какой-либо символ не совпадает, он переходит к следующей кодовой таблице в mb_detect_order() и повторяет попытку.

Список кодовых таблиц в Википедии - хорошее место для просмотра символов, входящих в каждую кодовую таблицу.

Поскольку значения этих кодовых таблиц пересекаются (символ x8fA1EF существует как в 'UTF-8', так и в 'EUC-JP'), он будет считаться совпадением, даже если это совершенно другой символ в каждом наборе символов. Таким образом, если ни одно из значений символов не существует в одном наборе символов, но не существует в другом, то mb_detect_encoding не сможет определить, какой из наборов символов недействителен; и вернет первый набор символов из вашего списка, который может быть действительным.

Насколько я знаю, не существует надежного способа определения кодовой таблицы. Метод "лучшего предположения" PHP может помочь, если вы имеете разумное представление о том, с какими кодировками вы можете столкнуться, и упорядочите свой список соответствующим образом, основываясь на пробелах (недопустимых символах) в каждой кодировке. Лучшее решение - "знать" кодировку. Если вы копируете html с другой страницы, найдите идентификатор кодировки в заголовке этой страницы.

Если вы действительно хотите быть умным, вы можете попытаться определить язык, на котором написан html, возможно, используя триграммы, n-граммы или что-то подобное, как описано в этой статье о PHP/ir.

1
ответ дан 6 December 2019 в 19:33
поделиться

Не совсем. Различные кодировки часто имеют большие области перекрытия, и если ваша строка, которую вы тестируете, существует полностью внутри этого перекрытия, то обе кодировки приемлемы.

Например, utf-8 и ISO-8859-1 совпадают для букв a-z. Строка «hello» будет иметь идентичную последовательность байтов в обеих кодировках.

Именно поэтому существует функция mb_detect_order () , так как она позволяет вам сказать, что вы бы предпочли, когда происходят эти конфликты. Вы хотите, чтобы "привет" было utf-8 или ISO-8859-1?

5
ответ дан 6 December 2019 в 19:33
поделиться

Следует помнить, что mb_detect_encoding() не знает, в какой кодировке находятся данные. Вы можете видеть строку, но сама функция видит только поток байтов. Исходя из этого, она должна угадать кодировку - например, ASCII - если байты находятся только в диапазоне 0-127, UTF-8 - если есть байты ASCII и байты 128+, которые существуют только в парах или более, и т.д.

Как вы можете себе представить, учитывая этот контекст, довольно трудно надежно определить кодировку.

Как сказал rihk, для этого и нужна функция mb_detect_order() - вы в основном предоставляете свое лучшее предположение о том, какими могут быть данные. Вы часто работаете с файлами UTF-8? Тогда есть шанс, что ваши данные не будут UTF-16, даже если mb_detect_encoding() сможет определить их как таковые.

Возможно, вы также захотите проверить Artefacto по ссылке для более подробного обзора.

Пример: Internet Explorer использует интересный способ угадывания кодировки, если ничего не указано (@link, Section: 'To automatically detect a website's language'), который вызвал странное поведение на сайтах, которые в прошлом принимали кодировку как должное. Если погуглить, можно найти забавные материалы на эту тему. Это хороший пример того, как даже статистические методы могут дать ужасный обратный эффект, и почему угадывание кодировки в целом проблематично.

2
ответ дан 6 December 2019 в 19:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: