У меня проблема с удалением из строки символов, отличных от utf8, которые не отображаются должным образом. Символы такие: 0x97 0x61 0x6C 0x6F (шестнадцатеричное представление)
Как лучше всего их удалить? Регулярное выражение или что-то еще?
Перечисленные здесь решения не сработали для меня, поэтому я нашел свой ответ здесь, в разделе «Проверка персонажа»: webcollab.sourceforge.net/unicode.html
bobef
Связанный с этим , но не обязательно дубликат, скорее близкий родственник :)
Он ищет последовательности 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);
что использовать вместо $regex = <<<'END'PHP <5.3.x?
serhio,
Вместо этого вы можете преобразовать их в формат heredoc с небольшим ухудшением читаемости. Другой вариант - использовать строки в одинарных кавычках, но тогда вам придется удалить комментарии.
Маркус Джардерот
В этой строке есть небольшая опечатка, elseif (!empty($captures([2])) {и вы должны использовать !== ""вместо empty, так как "0"это считается пустым. Также эта функция работает очень медленно, можно ли это сделать быстрее?
Кендалл Хопкинс,
2
Это выражение имеет серьезную проблему с памятью, см. Здесь .
Ja͢ck
1
@MarkusJarderot, Regex ....... хм, эта функция готова к производству? Есть ли тестовые примеры для этой функции?
Pacerier
133
Если вы примените utf8_encode()к уже существующей строке UTF8, она вернет искаженный вывод UTF8.
Я сделал функцию, которая решает все эти проблемы. Это называется Encoding::toUTF8().
Вам не нужно знать, какова кодировка ваших строк. Это может быть Latin1 (ISO8859-1), Windows-1252 или UTF8, либо строка может содержать их сочетание. Encoding::toUTF8()конвертирует все в UTF8.
Я сделал это, потому что служба давала мне поток данных, которые были перепутаны, смешивая эти кодировки в одной строке.
Я включил еще одну функцию, Encoding :: fixUTF8 (), которая исправит каждую строку UTF8, которая выглядит искаженным результатом многократного кодирования в UTF8.
@Alliswell Если я не ошибаюсь <0x1a>, хотя и не печатаемый символ, это вполне допустимая последовательность UTF-8. У вас могут быть проблемы с непечатаемыми символами? Проверьте это: stackoverflow.com/questions/1176904/…
Frosty Z
да, это так. Спасибо друг!
Alliswell
Перед вызовом mb convert мне пришлось установить для символа замены mbstring значение none, ini_set('mbstring.substitute_character', 'none');иначе в результате я получал вопросительные знаки.
cby016 07
22
Эта функция удаляет все символы НЕ ASCII, она полезна, но не решает вопроса:
это моя функция, которая всегда работает, независимо от кодировки:
Этот сработал. Я столкнулся с проблемой, когда API Карт Google сообщил об ошибке из-за «символа, отличного от UTF-8» в URL-адресе запроса API. Виновником был íсимвол в поле адреса, который является допустимым символом UTF-8 ( см. Таблицу) . Моральный дух: не доверяйте сообщениям об ошибках API :)
Согласно руководству iconv , функция будет принимать первый параметр как кодировку ввода, второй параметр как кодировку вывода, а третий как фактическую строку ввода.
Если вы установите как входную, так и выходную кодировку в UTF-8 и добавите //IGNOREфлаг к выходной кодировке, функция отбросит (уберет) все символы во входной строке, которые не могут быть представлены выходной кодировкой. Таким образом, действует фильтрация входной строки.
Объясните, что делает ваш ответ, вместо того, чтобы сбрасывать фрагмент кода.
Tomasz Kowalczyk
3
Я пробовал это, и //IGNORE, похоже, он не подавляет уведомление о том, что присутствует недопустимый UTF-8 (о котором, конечно, я знаю и хочу исправить). Комментарий в руководстве с высокой оценкой, кажется, считает, что это была ошибка в течение нескольких лет.
Halfer
Всегда лучше использовать iconv. @halfer Может быть, ваши входные данные не из UTF-8. Другой вариант - выполнить повторное преобразование в ascii, а затем снова обратно в utf-8. В моем случае я использовал iconvкак$output = iconv("UTF-8//", "ISO-8859-1//IGNORE", $input );
m3nda
@ erm3nda: я точно не помню свой вариант использования для этого - возможно, разбор веб-сайта UTF-8 был объявлен с неправильной кодировкой. Спасибо за заметку, уверен, что она будет полезна будущему читателю.
Halfer
Да, если вы чего-то не знаете, просто проверьте это и, наконец, вы нажмете клавишу ;-)
m3nda
9
Текст может содержать символы, отличные от UTF8 . Попробуйте сначала сделать:
UConverter можно использовать, начиная с PHP 5.5. UConverter - лучший выбор, если вы используете расширение intl и не используете mbstring.
function replace_invalid_byte_sequence($str){returnUConverter::transcode($str,'UTF-8','UTF-8');}function replace_invalid_byte_sequence2($str){return(newUConverter('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'));}
У вас есть три хороших решения, но непонятно, как пользователь выберет одно из них.
Боб Рэй
6
Я сделал функцию, которая удаляет недопустимые символы UTF-8 из строки. Я использую его, чтобы очистить описание 27000 продуктов перед созданием файла экспорта XML.
Из всех приведенных выше сложных ответов этот помог мне! Спасибо.
Эмин Озлем
Меня смущает эта функция. ord()возвращает результаты в диапазоне 0–255. Гигант ifв этой функции проверяет диапазоны Unicode, ord()которые никогда не вернутся. Если кто-то хочет уточнить, почему эта функция работает именно так, я был бы признателен за понимание.
i336_
4
Добро пожаловать в 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 chars\r \x00"];foreach($arr as $k => $v){
echo "$k:\n---------\n";
$len = strlen($v);
echo "$v\n(".$len.")\n";
$strip = utf8_decode(utf8_filter(utf8_encode($v)));
$strip_len = strlen($strip);
echo $strip."\n(".$strip_len.")\n\n";
echo "Chars removed: ".($len - $strip_len)."\n\n\n";}
Если вас это беспокоит, да, он сохраняет пробелы как допустимые символы.
Сделал то, что мне нужно. Он удаляет широко распространенные в настоящее время эмодзи-символы, которые не вписываются в набор символов MySQL «utf8» и выдают мне такие ошибки, как «SQLSTATE [HY000]: Общая ошибка: 1366 Неверное строковое значение».
После того, как вы попробовали сотни решений, единственное, что сработало, - ваше.
Haritsinh Gohil,
1
Таким образом, правила таковы, что первый октлет UTF-8 имеет старший бит, установленный в качестве маркера, а затем от 1 до 4 битов, чтобы указать, сколько дополнительных октлетов; тогда для каждого из дополнительных октлетов два старших бита должны быть установлены на 10.
Псевдо-питон будет:
newstring =''
cont =0for each ch instring: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 -=1else:if(ch >>7):# high bit set?
c =(ch <<1)# strip the high bit markerwhile(c &1):# while the high bit indicates another octlet
c <<=1
cont +=1if cont >4:# more than 4 octels not allowed; cope with errorif!cont:# illegal, do something sensible
newstring += ch # or whateverif cont:# last utf-8 was not terminated, cope
Та же самая логика должна быть переведена на php. Однако неясно, какое удаление нужно делать, когда вы получаете искаженный персонаж.
Ответы:
Используя подход регулярного выражения:
Он ищет последовательности UTF-8 и захватывает их в группу 1. Он также сопоставляет отдельные байты, которые не могут быть идентифицированы как часть последовательности UTF-8, но не захватывает их. Замена - это то, что было записано в группу 1. Это эффективно удаляет все недопустимые байты.
Строку можно исправить, закодировав недопустимые байты как символы UTF-8. Но если ошибки случайны, это может привести к появлению странных символов.
РЕДАКТИРОВАТЬ:
!empty(x)
будет соответствовать непустым значениям ("0"
считается пустым).x != ""
будет соответствовать непустым значениям, включая"0"
.x !== ""
будет соответствовать чему угодно, кроме""
.x != ""
кажется лучшим вариантом в этом случае.Я также немного ускорил матч. Вместо сопоставления каждого символа по отдельности он сопоставляет последовательности допустимых символов UTF-8.
источник
$regex = <<<'END'
PHP <5.3.x?elseif (!empty($captures([2])) {
и вы должны использовать!== ""
вместо empty, так как"0"
это считается пустым. Также эта функция работает очень медленно, можно ли это сделать быстрее?Если вы примените
utf8_encode()
к уже существующей строке UTF8, она вернет искаженный вывод UTF8.Я сделал функцию, которая решает все эти проблемы. Это называется
Encoding::toUTF8()
.Вам не нужно знать, какова кодировка ваших строк. Это может быть Latin1 (ISO8859-1), Windows-1252 или UTF8, либо строка может содержать их сочетание.
Encoding::toUTF8()
конвертирует все в UTF8.Я сделал это, потому что служба давала мне поток данных, которые были перепутаны, смешивая эти кодировки в одной строке.
Использование:
Я включил еще одну функцию, Encoding :: fixUTF8 (), которая исправит каждую строку UTF8, которая выглядит искаженным результатом многократного кодирования в UTF8.
Использование:
Примеры:
выведет:
Скачать:
https://github.com/neitanod/forceutf8
источник
Вы можете использовать mbstring:
... удалит недопустимые символы.
См .: Замена недопустимых символов UTF-8 вопросительными знаками, mbstring.substitute_character игнорируется
источник
<0x1a>
<0x1a>
, хотя и не печатаемый символ, это вполне допустимая последовательность UTF-8. У вас могут быть проблемы с непечатаемыми символами? Проверьте это: stackoverflow.com/questions/1176904/…ini_set('mbstring.substitute_character', 'none');
иначе в результате я получал вопросительные знаки.Эта функция удаляет все символы НЕ ASCII, она полезна, но не решает вопроса:
это моя функция, которая всегда работает, независимо от кодировки:
Как это устроено:
источник
í
символ в поле адреса, который является допустимым символом UTF-8 ( см. Таблицу) . Моральный дух: не доверяйте сообщениям об ошибках API :)Это то, что я использую. Кажется, работает очень хорошо. Взято с http://planetozh.com/blog/2005/01/remove-invalid-characters-in-utf-8/
источник
попробуй это:
Согласно руководству iconv , функция будет принимать первый параметр как кодировку ввода, второй параметр как кодировку вывода, а третий как фактическую строку ввода.
Если вы установите как входную, так и выходную кодировку в UTF-8 и добавите
//IGNORE
флаг к выходной кодировке, функция отбросит (уберет) все символы во входной строке, которые не могут быть представлены выходной кодировкой. Таким образом, действует фильтрация входной строки.источник
//IGNORE
, похоже, он не подавляет уведомление о том, что присутствует недопустимый UTF-8 (о котором, конечно, я знаю и хочу исправить). Комментарий в руководстве с высокой оценкой, кажется, считает, что это была ошибка в течение нескольких лет.iconv
. @halfer Может быть, ваши входные данные не из UTF-8. Другой вариант - выполнить повторное преобразование в ascii, а затем снова обратно в utf-8. В моем случае я использовалiconv
как$output = iconv("UTF-8//", "ISO-8859-1//IGNORE", $input );
Текст может содержать символы, отличные от UTF8 . Попробуйте сначала сделать:
Подробнее об этом можно прочитать здесь: http://php.net/manual/en/function.mb-convert-encoding.php news
источник
UConverter можно использовать, начиная с PHP 5.5. UConverter - лучший выбор, если вы используете расширение intl и не используете mbstring.
htmlspecialchars может использоваться для удаления недопустимой последовательности байтов, начиная с PHP 5.4. Htmlspecialchars лучше, чем preg_match, для обработки большого размера байта и точности. Можно увидеть много неправильной реализации с использованием регулярных выражений.
источник
Я сделал функцию, которая удаляет недопустимые символы UTF-8 из строки. Я использую его, чтобы очистить описание 27000 продуктов перед созданием файла экспорта XML.
источник
ord()
возвращает результаты в диапазоне 0–255. Гигантif
в этой функции проверяет диапазоны Unicode,ord()
которые никогда не вернутся. Если кто-то хочет уточнить, почему эта функция работает именно так, я был бы признателен за понимание.Добро пожаловать в 2019 год и
/u
модификатор в регулярном выражении, который будет обрабатывать многобайтовые символы UTF-8 за вас.Если вы используете только,
mb_convert_encoding($value, 'UTF-8', 'UTF-8')
вы все равно получите непечатаемые символы в вашей строкеЭтот метод будет:
mb_convert_encoding
\r
,\x00
(NULL-байт) и другие символы управления сpreg_replace
метод:
[:print:]
сопоставьте все печатаемые символы и символы\n
новой строки и удалите все остальноеВы можете увидеть таблицу ASCII ниже. Печатные символы варьируются от 32 до 127, но новая строка
\n
является частью управляющих символов, которые варьируются от 0 до 31, поэтому мы должны добавить новую строку в регулярное выражение/[^[:print:]\n]/u
Вы можете попробовать отправить строки через регулярное выражение с символами за пределами диапазона печати, например
\x7F
(DEL),\x1B
(Esc) и т. Д., И посмотреть, как они удаляютсяhttps://www.tehplayground.com/q5sJ3FOddhv1atpR
источник
php-mbstring
который по умолчанию не упакован в php.источник
Из недавнего патча к модулю парсера JSON каналов Drupal:
Если вас это беспокоит, да, он сохраняет пробелы как допустимые символы.
Сделал то, что мне нужно. Он удаляет широко распространенные в настоящее время эмодзи-символы, которые не вписываются в набор символов MySQL «utf8» и выдают мне такие ошибки, как «SQLSTATE [HY000]: Общая ошибка: 1366 Неверное строковое значение».
Подробнее см. Https://www.drupal.org/node/1824506#comment-6881382.
источник
iconv
намного лучше, чем устаревшее, основанное на регулярных выраженияхpreg_replace
, которое в настоящее время не рекомендуется.ereg_replace()
, извините.Возможно, не самое точное решение, но оно выполняет свою работу с помощью одной строчки кода:
utf8_decode
преобразует символы в вопросительный знак;str_replace
удалит вопросительные знаки.источник
Таким образом, правила таковы, что первый октлет UTF-8 имеет старший бит, установленный в качестве маркера, а затем от 1 до 4 битов, чтобы указать, сколько дополнительных октлетов; тогда для каждого из дополнительных октлетов два старших бита должны быть установлены на 10.
Псевдо-питон будет:
Та же самая логика должна быть переведена на php. Однако неясно, какое удаление нужно делать, когда вы получаете искаженный персонаж.
источник
c = (ch << 1)
сделает(c & 1)
ноль в первый раз, пропуская цикл. Тест, вероятно, должен быть(c & 128)
Чтобы удалить все символы Unicode за пределами базовой языковой плоскости Unicode:
источник
Немного отличается от вопроса, но я использую HtmlEncode (строка),
здесь псевдокод
ввод и вывод
Я знаю, что это не идеально, но работает за меня.
источник
это работает на нашем сервисе
источник
Как насчет iconv:
http://php.net/manual/en/function.iconv.php
Я не использовал его внутри самого PHP, но он всегда хорошо работал в командной строке. Вы можете заставить его заменять недопустимые символы.
источник