Удалить символы не-utf8 из строки

Вопрос:У меня проблема с удалением не-utf8 символов из строки, которые отображаются неправильно. Символы подобны 0x97 0x61 0x6C 0x6F (шестнадцатеричное представление) Каков наилучший способ их удаления? Регулярное выражение или что-то еще? Лучший ответ: Использование подхода с регулярным выражением: $regex =

Вопрос:

У меня проблема с удалением не-utf8 символов из строки, которые отображаются неправильно. Символы подобны 0x97 0x61 0x6C 0x6F (шестнадцатеричное представление)

Каков наилучший способ их удаления? Регулярное выражение или что-то еще?

Лучший ответ:

Использование подхода с регулярным выражением:

$regex = <<<‘END’ / ( (?: [x00-x7F] # single-byte sequences 0xxxxxxx | [xC0-xDF][x80-xBF] # double-byte sequences 110xxxxx 10xxxxxx | [xE0-xEF][x80-xBF]{2} # triple-byte sequences 1110xxxx 10xxxxxx * 2 | [xF0-xF7][x80-xBF]{3} # quadruple-byte sequence 11110xxx 10xxxxxx * 3 ){1,100} # …one or more times ) | . # anything else /x END; preg_replace($regex, ‘$1’, $text);

Он ищет последовательности UTF-8 и захватывает их в группу 1. Он также соответствует одиночным байтам, которые не могут быть идентифицированы как часть последовательности UTF-8, но не захватывают их. Замена – это то, что было записано в группу 1. Это эффективно удаляет все недопустимые байты.

Можно восстановить строку, закодировав недопустимые байты как символы UTF-8. Но если ошибки случайны, это может оставить некоторые странные символы.

$regex = <<<‘END’ / ( (?: [x00-x7F] # single-byte sequences 0xxxxxxx | [xC0-xDF][x80-xBF] # double-byte sequences 110xxxxx 10xxxxxx | [xE0-xEF][x80-xBF]{2} # triple-byte sequences 1110xxxx 10xxxxxx * 2 | [xF0-xF7][x80-xBF]{3} # quadruple-byte sequence 11110xxx 10xxxxxx * 3 ){1,100} # …one or more times ) | ( [x80-xBF] ) # invalid byte in range 10000000 — 10111111 | ( [xC0-xFF] ) # invalid byte in range 11000000 — 11111111 /x END; function utf8replacer($captures) { if ($captures[1] != «») { // Valid byte sequence. Return unmodified. return $captures[1]; } elseif ($captures[2] != «») { // Invalid byte of the form 10xxxxxx. // Encode as 11000010 10xxxxxx. return «xC2».$captures[2]; } else { // Invalid byte of the form 11xxxxxx. // Encode as 11000011 10xxxxxx. return «xC3».chr(ord($captures[3])-64); } } preg_replace_callback($regex, «utf8replacer», $text);

EDIT:

  • !empty(x) будет соответствовать непустым значениям («0» считается пустым).
  • x != «» будет соответствовать непустым значениям, включая «0».
  • x !== «» будет соответствовать всем, кроме «».

x != «» кажется лучшим в этом случае.

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

Ответ №1

Если вы примените utf8_encode() к уже строке UTF8, она вернет искаженный вывод UTF8.

Я сделал функцию, которая решает все эти проблемы. Он называется Encoding::toUTF8().

Вам не нужно знать, какова кодировка ваших строк. Это может быть Latin1 (ISO8859-1), Windows-1252 или UTF8, или в строке может быть их сочетание. Encoding::toUTF8() преобразует все в UTF8.

Я сделал это, потому что служба давала мне поток данных, которые все перепутали, смешивая эти кодировки в одной строке.

Использование:

require_once(‘Encoding.php’); use ForceUTF8Encoding; // It namespaced now. $utf8_string = Encoding::toUTF8($mixed_string); $latin1_string = Encoding::toLatin1($mixed_string);

Я включил еще одну функцию, Encoding :: fixUTF8(), которая будет фиксировать каждую строку UTF8, которая выглядит искаженным продуктом, потому что она была закодирована в UTF8 несколько раз.

Использование:

require_once(‘Encoding.php’); use ForceUTF8Encoding; // It namespaced now. $utf8_string = Encoding::fixUTF8($garbled_utf8_string);

Примеры:

echo Encoding::fixUTF8(«Fédération Camerounaise de Football»); echo Encoding::fixUTF8(«Fédération Camerounaise de Football»); echo Encoding::fixUTF8(«FÃÂédÃÂération Camerounaise de Football»); echo Encoding::fixUTF8(«Fédération Camerounaise de Football»);

выведет:

Fédération Camerounaise de Football Fédération Camerounaise de Football Fédération Camerounaise de Football Fédération Camerounaise de Football

Скачать:

https://github.com/neitanod/forceutf8

Ответ №2

Вы можете использовать mbstring:

$text = mb_convert_encoding($text, ‘UTF-8’, ‘UTF-8’);

… удалит недопустимые символы.

Смотрите: Замена недопустимых символов UTF-8 вопросительными знаками, mbstring.substitute_character кажется проигнорированным

Ответ №3

Эта функция удаляет все символы NON ASCII, это полезно, но не решает вопрос:
Это моя функция, которая всегда работает независимо от кодировки:

function remove_bs($Str) { $StrArr = str_split($Str); $NewStr = »; foreach ($StrArr as $Char) { $CharNo = ord($Char); if ($CharNo == 163) { $NewStr .= $Char; continue; } // keep £ if ($CharNo > 31 && $CharNo < 127) { $NewStr .= $Char; } } return $NewStr; }

Как это работает:

echo remove_bs(‘Hello õhowå åare youÆ?’); // Hello how are you? Ответ №4$text = iconv(«UTF-8», «UTF-8//IGNORE», $text);

Это то, что я использую. Кажется, работает очень хорошо. Взято из http://planetozh.com/blog/2005/01/remove-invalid-characters-in-utf-8/

Ответ №5

попробуйте следующее:

$string = iconv(«UTF-8″,»UTF-8//IGNORE»,$string);

В соответствии с iconv manual, функция примет первый параметр в качестве входной кодировки, второй параметр в качестве выходной кодировки и третий как фактическая строка ввода.

Если вы установите как кодировку ввода и вывода на UTF-8, так и добавьте флаг //IGNORE к выходной кодировке, функция отбросит (разделит) все символы в строке ввода, которые не может быть представлена ​​выходной кодировкой. Таким образом, фильтрация входной строки в действии.

Ответ №6

Текст может содержать символ не-utf8. Сначала попробуйте:

$nonutf8 = mb_convert_encoding($nonutf8 , ‘UTF-8’, ‘UTF-8’);

Подробнее об этом можно прочитать здесь: http://php.net/manual/en/function.mb-convert-encoding.php news

Ответ №7

UConverter можно использовать с PHP 5.5. UConverter лучше выбирать, если вы используете расширение intl и не используете mbstring.

function replace_invalid_byte_sequence($str) { return UConverter::transcode($str, ‘UTF-8’, ‘UTF-8’); } function replace_invalid_byte_sequence2($str) { return (new UConverter(‘UTF-8’, ‘UTF-8’))->convert($str); }

htmlspecialchars можно использовать для удаления недопустимой последовательности байтов с PHP 5.4. Htmlspecialchars лучше, чем preg_match для обработки большого размера байта и точности. Можно увидеть много неправильной реализации, используя регулярное выражение.

function replace_invalid_byte_sequence3($str) { return htmlspecialchars_decode(htmlspecialchars($str, ENT_SUBSTITUTE, ‘UTF-8’)); } Ответ №8

Я создал функцию, которая удаляет недопустимые символы UTF-8 из строки.
Я использую его, чтобы очистить описание 27000 продуктов, прежде чем он создаст файл экспорта XML.

public function stripInvalidXml($value) { $ret = «»; $current; if (empty($value)) { return $ret; } $length = strlen($value); for ($i=0; $i < $length; $i++) { $current = ord($value{$i}); if (($current == 0x9) || ($current == 0xA) || ($current == 0xD) || (($current >= 0x20) && ($current <= 0xD7FF)) || (($current >= 0xE000) && ($current <= 0xFFFD)) || (($current >= 0x10000) && ($current <= 0x10FFFF))) { $ret .= chr($current); } else { $ret .= «»; } } return $ret; } Ответ №9$string = preg_replace(‘~&([a-z]{1,2})(acute|cedil|circ|grave|lig|orn|ring|slash|th|tilde|uml);~i’, ‘$1’, htmlentities($string, ENT_COMPAT, ‘UTF-8’)); Ответ №10

От недавнего патча к Drupal Feeds Модуль JSON-парсера:

//remove everything except valid letters (from any language) $raw = preg_replace(‘/(?:\\u[pLp{Zs}])+/’, », $raw);

Если вы обеспокоены да, он сохраняет пробелы как допустимые символы.

Сделал то, что мне было нужно. Он удаляет широко распространенные в настоящее время символы emoji, которые не вписываются в набор символов MySQL ‘utf8’, и это давало мне такие ошибки, как “SQLSTATE [HY000]: Общая ошибка: 1366 Неверное строковое значение”.

Подробнее см.

Ответ №11

Итак, правила состоят в том, что первый UTF-8 octlet имеет высокий бит, установленный как маркер, а затем от 1 до 4 бит до указать количество дополнительных октетов; то каждый из дополнительных октов должен иметь два бита с высоким значением, равным 10.

Псевдо-питон будет:

newstring = » cont = 0 for each ch in string: if cont: if (ch >> 6) != 2: # high 2 bits are 10 # do whatever, e.g. skip it, or skip whole point, or? else: # acceptable continuation of multi-octlet char newstring += ch cont -= 1 else: if (ch >> 7): # high bit set? c = (ch << 1) # strip the high bit marker while (c & 1): # while the high bit indicates another octlet c <<= 1 cont += 1 if cont > 4: # more than 4 octels not allowed; cope with error if !cont: # illegal, do something sensible newstring += ch # or whatever if cont: # last utf-8 was not terminated, cope

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

Ответ №12

Чтобы удалить все символы Unicode за пределами базовой плоскости Unicode:

$str = preg_replace(«/[^\x00-\xFFFF]/», «», $str); Ответ №13

Немного отличается от вопроса, но то, что я делаю, это использовать HtmlEncode (string),

псевдо-код здесь

var encoded = HtmlEncode(string); encoded = Regex.Replace(encoded, «&#d+?;», «»); var result = HtmlDecode(encoded);

вход и выход

«Headlightx007E Bracket, &#123; Cafe Racer<> Style, Stainless Steel 中文呢?» «Headlight~ Bracket, &#123; Cafe Racer<> Style, Stainless Steel 中文呢?»

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

Ответ №14

Добро пожаловать в 2019 и модификатор /u в регулярных выражениях, который будет обрабатывать многобайтовые символы UTF-8 для вас

Если вы используете только mb_convert_encoding($value, ‘UTF-8’, ‘UTF-8’), у вас все равно останутся непечатаемые символы в вашей строке

Этот метод будет:

  • Удалите все недопустимые многобайтовые символы UTF-8 с помощью mb_convert_encoding
  • Удалите все непечатаемые символы, такие как r, x00 (NULL-байт) и другие контрольные символы с помощью preg_replace

Метод:

function utf8_filter(string $value): string{ return preg_replace(‘/[^[:print:]n]/u’, », mb_convert_encoding($value, ‘UTF-8’, ‘UTF-8’)); }

[:print:] сопоставляет все печатные символы и n переводы строк и удаляет все остальное

Вы можете увидеть таблицу ASCII ниже. Печатные символы варьируются от 32 до 127, но символ новой строки n является частью контрольных символов, которые варьируются от 0 до 31, поэтому мы должны добавить новую строку в регулярное выражение /[^[:print:]n]/u

Вы можете попытаться отправить строки через регулярное выражение с символами за пределами диапазона печати, например x7F (DEL), x1B (Esc) и т.д., И посмотреть, как они удаляются

function utf8_filter(string $value): string{ return preg_replace(‘/[^[:print:]n]/u’, », mb_convert_encoding($value, ‘UTF-8’, ‘UTF-8’)); } $arr = [ ‘Danish chars’ => ‘Hello from Denmark with æøå’, ‘Non-printable chars’ => «x7FHello with invalid charsr x00» ]; foreach($arr as $k => $v){ echo «$k:n———n»; $len = strlen($v); echo «$vn(«.$len.»)n»; $strip = utf8_decode(utf8_filter(utf8_encode($v))); $strip_len = strlen($strip); echo $strip.»n(«.$strip_len.»)nn»; echo «Chars removed: «.($len — $strip_len).»nnn»; }

https://www.tehplayground.com/q5sJ3FOddhv1atpR

Ответ №15

Как насчет iconv:

http://php.net/manual/en/function.iconv.php

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

Оцените статью
Добавить комментарий