Странное поведение mb_detect_order () в PHP - PullRequest
7 голосов
/ 21 мая 2010

Я хотел бы обнаружить кодировку некоторого текста (используя 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 способ правильно и однозначно определить кодировку текста?

Ответы [ 4 ]

5 голосов
/ 21 мая 2010

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

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

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

5 голосов
/ 21 мая 2010

Это то, что я ожидал бы.

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

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

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

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

2 голосов
/ 21 мая 2010

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

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

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

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

Пример case : Internet Explorer использует некоторые интересные кодовые предположения, если ничего не указано (@link, Раздел: «Для автоматического определения языка сайта»), что вызывало странное поведение на сайтах в прошлом кодирование считалось само собой разумеющимся. Вы можете найти что-нибудь забавное, если будете гуглить. Это хороший пример того, как даже статистические методы могут иметь неприятные последствия, и почему угадывание кодирования в целом проблематично.

1 голос
/ 21 мая 2010

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

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...