кодирование в UTF-8 - есть ли окончательное решение?
Я просмотрел весь Интернет, я просмотрел SO, документацию по PHP и многое другое.
Кажется нелепой проблемой, для которой нет стандартного решения. Если вы получаете неизвестный набор символов, и в нем есть странные символы (например, английские кавычки), существует ли стандартный способ преобразовать их в UTF-8?
Я видел много грязных решений, использующих множество функций и проверок, и ни одно из них определенно не будет работать.
Кто-нибудь придумал свой собственная функция или решение, которое всегда работает?
РЕДАКТИРОВАТЬ
Многие люди отвечали, что "это неразрешимо" или что-то в этом роде. Я понимаю это сейчас, но никто не дал никакого решения, которое работало бы, кроме utf8_encode
, которое очень ограничено. Какие существуют методы борьбы с этим? Что такое лучший метод?
4 answers
Причина, по которой вы видели так много сложных решений этой проблемы, заключается в том, что по определению она неразрешима. Процесс кодирования строки текста не является детерминированным. Можно создавать различные комбинации текста и кодировок, которые приводят к одному и тому же потоку байтов. Поэтому, строго говоря, логически невозможно определить кодировку, набор символов и текст из потока байтов.
В действительности можно достичь результатов, которые являются "достаточно близкими", используя эвристические методы, потому что существует конечный набор кодировок, с которыми вы столкнетесь в дикой природе, и с достаточно большим образцом программа может определить наиболее вероятную кодировку. Будут ли результаты достаточно хорошими, зависит от приложения.
Я действительно хочу прокомментировать вопрос о пользовательских данных. Все данные, опубликованные с веб-страницы, имеют известную кодировку (сообщение поставляется с кодировкой, определенной разработчиком для страницы). Если пользователь вставляет текст в поле формы, браузер будет интерпретировать текст на основе кодировки исходных данных (как известно операционной системе) и кодировки страницы, и при необходимости перекодировать его. Слишком поздно определять кодировку на сервере - потому что браузер, возможно, изменил поток байтов на основе предполагаемой кодировки.
Например, если я наберу букву Ä на своей немецкой клавиатуре и опубликую ее на странице в кодировке UTF-8, на сервер будет отправлено 2 байта (XC3 x84). Это допустимая строка EBCDIC, представляющая букву C и d. Это также допустимая строка ANSI, которая представляет 2 символа "и". Однако, независимо от того, что я пытаюсь, невозможно вставить строку в кодировке ANSI в форму браузера и ожидать, что она будет интерпретироваться как UTF-8 - потому что операционная система знает, что я вставляю ANSI (я скопировал текст с Textpad, где я создал текстовый файл в кодировке ANSI) и перекодирует его в UTF-8, в результате чего поток байтов xC3 x83 x2 x80 x9E.
Я хочу сказать, что если пользователю удается публиковать мусор, это, возможно, потому, что он уже был мусором в то время, когда он был вставлен в форму браузера, потому что у клиента не было надлежащей поддержки набора символов, кодировки, чего угодно. Поскольку кодировка символов не является детерминированной, вы не можете ожидать, что в такой ситуации существует тривиальный метод обнаружения.
К сожалению, для загруженных файлов проблема остается. Единственное надежное решение, которое я см., чтобы показать пользователю раздел файла и спросить, правильно ли он был интерпретирован, и перебирать множество различных кодировок, пока это не произойдет.
Или мы могли бы разработать эвристический метод, который рассматривает появление определенных символов в разных языках. Допустим, я загрузил свой текстовый файл, содержащий два байта xC3 x84. Другой информации нет - всего два байта в файле. Этот метод мог бы обнаружить, что буква Ä довольно распространена в немецком тексте, но буквы "и" вместе встречаются редко на любом языке и, таким образом, определяют, что кодировка моего файла действительно UTF-8. Это грубый уровень сложности, с которым приходится иметь дело такому эвристическому методу, и чем больше статистических и лингвистических фактов он может использовать, тем надежнее будут его результаты.
Нет. Всегда нужно знать, в каком наборе символов находится строка. Угадывание набора символов с помощью функции обнюхивания ненадежно (хотя в большинстве ситуаций в западном мире обычно происходит путаница между ISO-8859-1 и UTF-8).
Но почему вам приходится иметь дело с неизвестными наборами символов? Для этого нет общего решения, потому что общая проблема не должна существовать в первую очередь. Каждая веб-страница и источник данных могут и должны иметь определение набора символов, а если нет, то следует попросить администратора этого ресурса добавить его.
(Не хочу показаться умником, но это единственный способ справиться с этим хорошо.)
Пекка прав насчет ненадежности, но если вам нужно решение и вы готовы рискнуть, и у вас есть доступная библиотека mbstring, этот фрагмент должен работать:
function forceToUtf8($string) {
if (!mb_check_encoding($string)) {
return false;
}
return mb_convert_encoding($string, 'UTF-8', mb_detect_encoding($string));
}
Если я не ошибаюсь, есть что-то под названием utf8encode... это хорошо работает, ЗА исключением случаев, когда вы уже находитесь в utf8