Подтвердить что ты не робот

Как очистить недействительный UTF-8 в Perl?

Моя программа Perl принимает некоторый текст из файла диска в качестве ввода, обертывает его в некоторый XML, а затем выводит его в STDOUT. Вход номинально UTF-8, но иногда вставляется старая. Мне нужно дезинфицировать вывод таким образом, чтобы не было выбрано ни одного недопустимого октета UTF-8, в противном случае потребитель вниз (Sphinx) взорвется.

По крайней мере, я хотел бы знать, недействительны ли данные, поэтому я могу избежать его передачи; В идеале я мог удалить только оскорбительные байты. Тем не менее, включение всех фатализмов, которые я могу найти, не приводит меня туда с perl 5.12 (FWIW, use v5.12; use warnings qw( FATAL utf8 );).

У меня возникают проблемы с последовательностью "\xFE\xBF\xBE". Если я создаю файл, содержащий только эти три байта (perl -e 'print "\xEF\xBF\xBE"' > bad.txt), пытаясь прочитать файл с ошибками :encoding(UTF-8) в режиме :encoding(UTF-8) с utf8 "\xFFFE" does not map to Unicode, но только под 5.14.0. 5.12.3 и более ранние - это прекрасное чтение и последующая запись этой последовательности. Я не уверен, откуда он получает \xFFFE (незаконную обратную спецификацию), но, по крайней мере, жалоба совместима с Sphinx.

К сожалению, decode_utf8("\xEF\xBF\xBE", 1) не вызывает ошибок в 5.12 или 5.14. Я бы предпочел метод обнаружения, который не требовал кодированного уровня ввода-вывода, поскольку это просто оставит меня с сообщением об ошибке и не будет дезинфицировать необработанные октеты.

Я уверен, что есть несколько последовательностей, которые мне нужно адресовать, но просто обработка этого была бы началом. Поэтому я задаю следующие вопросы: могу ли я надежно обнаружить данные проблем с perl до 5.14? Какая процедура подстановки обычно может дезинфицировать почти UTF-8 в строгие UTF-8?

4b9b3361

Ответ 1

Вы должны прочитать UTF-8 vs. utf8 vs. UTF8 раздел Encode.

Подводя итог, Perl имеет два разных кодировки UTF-8. Его родная кодировка называется utf8 и в основном позволяет любой код, независимо от того, что стандарт Unicode говорит об этом кодеге.

Другая кодировка называется utf-8 (a.k.a. utf-8-strict). Это позволяет использовать только кодовые обозначения, которые указаны в качестве законных для обмена по стандарту Unicode.

"\xEF\xBF\xBE", когда интерпретируется как UTF-8, декодирует кодовую точку U + FFFE. Но это не легально для обмена в соответствии с Unicode, поэтому программы, которые строги по поводу таких вещей, жалуются.

Вместо использования decode_utf8 (который использует lax utf8), используйте decode с кодировкой utf-8. И прочитайте раздел Обработка неверных данных, чтобы увидеть различные способы обработки или жалобы на проблемы.

Обновление. Кажется, что некоторые версии Perl не жалуются на U + FFFE, даже при использовании кодировки utf-8-strict. Кажется, это ошибка. Вам просто нужно создать список кодовых страниц, которые Sphinx жалуется и отфильтровывает их вручную (например, tr).

Ответ 2

У вас есть строка utf8, содержащая некоторые недопустимые utf8...

Это заменяет его по умолчанию "bad char".

use Encode qw(decode encode);

my $octets    = decode('UTF-8', $malformed_utf8, Encode::FB_DEFAULT);

my $good_utf8 = encode('UTF-8', $octets,         Encode::FB_CROAK);