Intereting Posts
Можно ли пропустить параметры, которые имеют значения по умолчанию в вызове функции php (5)? Я хочу построить дерево с этим массивом. Это категории и подкатегории Id. Реализация поисковой системы сайта, которая ищет статические страницы Лучшие практики для Post-Redirect-Get (PRG) с MVC в PHP Как скопировать электронную почту с Gmail на мой сервер с помощью PHP IMAP? Добавьте «Watermark» к изображениям с помощью php Добавить префикс в auto-increment в mysql db Laravel 5 Carbon global Locale MYSQL: настройка таблицы сведений о профиле пользователя – лучшая практика Значение переменной Ajax для javascript Неожиданное поведение current () в цикле foreach Как использовать глобальный тип пространства имен, намекающий внутри класса с именами в PHP 5.3+? nginx переписывание с окнами drupal Как сериализовать пользователя в отношении аутентификации? Laravel 5 в конфигурации php artisan: сгенерирована сгенерированная ошибка Closure :: __ set_state ()

Как преобразовать текст с помощью HTML-адресов и недопустимых символов в эквивалент UTF-8?

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

Как преобразовать объекты HTML, символьные ссылки типа & # [0-9] +; и & # x [a-fA-F0-9] + ;, недопустимые ссылки на символы – и недопустимые символы Windows chr (151) на их эквиваленты UTF-8?

В основном, как очистить очень плохой текст переменной кодировки и сохранить его как UTF-8?

оригинальный вопрос ниже

Преобразовать & # [0-9] +; и & # x [a-fA-F0-9] +; ссылки на эквивалентные значения UTF-8?

например

— — 

к –

как это делает браузер, но с php.

edit: даже нестандартные, которые делают окна, но браузеры.

Отвечая на мой вопрос с решением, которое я использовал в конце

Проблема:

Мне нужно было заменить html-сущности и десятичные и шестнадцатеричные ссылки на символы, которые выглядели так: ‚ и ‚ и &#emdash; к их эквивалентам UTF-8, как обычный браузер, и преобразовать текст в UTF-8.

Проблема заключалась в том, что часто были ссылки, которые находились в диапазоне 130-150 и x82-x9F, которые, как выяснилось, были недопустимыми символами слова Windows, которые люди используют с текстом ASCII для специальных символов, таких как emdash, которые не поддерживаются php's html_entity_decode.

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

При попытке исправить эти ссылки я также выяснил, что используются фактические символы, такие как <?php echo chr(151);?> , Которые, вероятно, были непосредственно скопированы из слова, и вызовут всевозможные проблемы, поэтому мне нужно было их тоже исправлять.

Большинство ответов, которые я нашел в отношении кодировок, не упоминают, так это то, что решение проблемы с кодированием часто зависит от используемой кодировки. Вот пример:

Недопустимый символ окна chr(151) будет работать с кодированным текстом «ISO-8859-1», а Джош Б упоминает в соответствии с предложением Юкки Корпелас, что вы должны их исправить следующим образом:

 $str = str_replace(chr(151),'--',$str); 

То, что он делает, заменяет символ Windows на безопасную альтернативу ASCII, но, зная, что текст будет сохранен в UTF-8, я не хотел потерять исходные символы. Хотя их изменение не было возможным, поскольку ASCII не поддерживает нужный символ Unicode:

 $str = str_replace(chr(151),chr(8218),$str); 

Итак, вместо этого я заменил символ на ссылку html (в то время как $ str был «ISO-8859-1» закодирован:

 $str = str_replace(chr(151),'&#8218;'),$str); 

Затем я меняю кодировку

 $str = iconv('ISO-8859-1', 'UTF-8//IGNORE', $str);//convert to UTF-8 

И, наконец, я превращаю все сущности и символьные ссылки в чистый UTF-8 с помощью моей функции «html_character_reference_decode», которая в значительной степени основана на решении Gumbos , которая также исправляет плохие ссылки на окна, но использует только preg_replace_callback чтобы переходить с неправильными символами Windows.

 function fix_char_mapping($match){ if (strtolower($match[1][0]) === "x") { $codepoint = intval(substr($match[1], 1), 16); } else { $codepoint = intval($match[1], 10); } $mapping = array(8218,402,8222,8230,8224,8225,710,8240,352,8249,338,141,142,143,144,8216,8217,8220,8221,8226,8211,8212,732,8482,353,8250,339,157,158,376); $codepoint = $mapping[$codepoint-130]; return '&#'.$codepoint.';'; } function html_character_reference_decode($string, $encoding='UTF-8', $fixMappingBug=true){ if($fixMappingBug){ $string = preg_replace_callback('/&#(1[3-5][0-9]|x8[2-9a-f]|x9[0-9a-f]);/i','fix_char_mapping',$string); } return html_entity_decode($string, ENT_QUOTES, 'UTF-8'); } header('Content-Type: text; charset=UTF-8'); echo html_character_reference_decode('dash &#151; and another dash &#x97; text &#x5D5; and more tests &#x5E0;&#x5D5;&#x5E3; '); 

Поэтому, если ваш текст кодируется «ISO-8859-1», полное решение выглядит так:

 <?php header('Content-Type: text/plain; charset=utf-8'); ini_set("default_charset", 'utf-8'); error_reporting(-1); $encoding = 'ISO-8859-1';//put encoding here $str = '&#x9F; &#x9C; bad&#150;string: '.chr(151);//ASCII if($encoding==='ISO-8859-1'){ //fix bad windows characters $badchars = array( '&#130;'=>chr('130'),//',' baseline single quote '&#131;'=>chr('131'),//'NLG' florin '&#132;'=>chr('132'),//'"' baseline double quote '&#133;'=>chr('133'),//'...' ellipsis '&#134;'=>chr('134'),//'**' dagger (a second footnote) '&#135;'=>chr('135'),//'***' double dagger (a third footnote) '&#136;'=>chr('136'),//'^' circumflex accent '&#137;'=>chr('137'),//'o/oo' permile '&#138;'=>chr('138'),//'Sh' S Hacek '&#139;'=>chr('139'),//'<' left single guillemet '&#140;'=>chr('140'),//'OE' OE ligature '&#145;'=>chr('145'),//"'" left single quote '&#146;'=>chr('146'),//"'" right single quote '&#147;'=>chr('147'),//'"' left double quote '&#148;'=>chr('148'),//'"' right double quote '&#149;'=>chr('149'),//'-' bullet '&#150;'=>chr('150'),//'-' endash '&#151;'=>chr('151'),//'--' emdash '&#152;'=>chr('152'),//'~' tilde accent '&#153;'=>chr('153'),//'(TM)' trademark ligature '&#154;'=>chr('154'),//'sh' s Hacek '&#155;'=>chr('155'),//'>' right single guillemet '&#156;'=>chr('156'),//'oe' oe ligature '&#159;'=>chr('159'),//'Y' Y Dieresis ); $str = str_replace(array_values($badchars),array_keys($badchars),$str); $str = iconv('ISO-8859-1', 'UTF-8//IGNORE', $str);//convert to UTF-8 $str = html_character_reference_decode($str);//fixes bad entities above echo $str;die; } 

Он был протестирован с широким спектром ситуаций и выглядит так, как будто он работает.

Давайте рассмотрим ту же ситуацию с кодированным текстом UTF-8, который содержит неправильные символы Windows.

Один надежный способ проверить наличие плохих символов или «плохо сформированный UTF-8» состоял в том, чтобы использовать значок, он медленный, но был более надежным, чем использование preg_match в моих тестах:

 $cleaned = iconv('UTF-8','UTF-8//IGNORE',$str); if ($cleaned!==$str){ //contains bad characters, use cleaned version where the bad characters were stripped $str = $cleaned; } 

Это было в значительной степени лучшим, о чем я мог подумать, поскольку не нашел разумного способа найти и заменить символы плохого окна в тексте UTF-8, позвольте мне объяснить, почему.

позволяет взять строку с вполне допустимым символом Unicode $str = "—".chr(151); и плохие окна emdash.

Я не знаю, какие плохие символы Windows могут присутствовать в строке UTF-8, только чтобы они присутствовали.

Использование str_replace для исправления плохого символа окна chr(148) (правая двойная кавычка) в приведенной выше правильной строке emdash, которая даже не содержит никаких двойных кавычек, приведет к символу scrambeled, сначала я думал, что str_replace может не быть многобайтным и попытался использовать mb_eregi_replace но проблема была такой же.

Комментарии на веб-сайте php и stackoverflow str_replace о том, что str_replace безопасен двоично и отлично работает с хорошо сформированным текстом UTF-8 из-за того, что был разработан UTF-8.

Почему это ломается

Он показывает, что символ «плохой» окна chr(148) состоит из следующих битов « 10010100 », а символ (emdash) ( http://www.fileformat.info/info/unicode/char/2014/index.htm ), который согласно веб-сайту fileformat состоит из 3 байтов: «11100010: 10000000: 10010100 »

Обратите внимание, что биты в последнем байте в абсолютно правильном символе UTF-8 соответствуют битам в двойной двойной кавычки плохих окон, поэтому str_replace просто заменяет последний байт, нарушая символ UTF-8. Эта проблема возникает с большим количеством символов в Юникоде и, например, скремблирует много символов в русском тексте.

Это не может случиться с текстом ASCII, потому что каждый символ всегда состоит из одного байта.

Поэтому, когда вы получаете строку UTF-8, содержащую любое количество многобайтовых символов, вы больше не можете безопасно исправлять неправильные символы Windows, и единственным решением, которое я нашел, было удаление их с помощью iconv

 $str = iconv('UTF-8', 'UTF-8//IGNORE', $str); 

Единственное решение, о котором я могу думать

Хотя вы всегда можете заменить действительные символы юникода, содержащие байты плохих символов, на их закодированные копии, затем заменить плохие символы, а затем декодировать хорошие символы, тем самым сохраняя все 🙂

как это:

  1. замените 11100010:10000000:10010100 с кодировкой типа &#8212;
  2. затем замените 10010100 на правильную em dash &mdash;
  3. затем декодировать &#8212; назад к 11100010:10000000:10010100

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

Связано: Какая разница между EM Dash # 151; и # 8212 ;?

Это намного сложнее, чем я думал, когда я написал свой ответ.

Gumbo обновил свой ответ на очень похожий вопрос, поэтому просто прочитайте:

Как преобразовать ссылки на символы HTML (& # x5E3;) в обычный UTF-8?