¿Cómo desinfeto el UTF-8 no válido en Perl?
sanitization (2)
Mi programa Perl toma un texto de un archivo de disco como entrada, lo envuelve en un poco de XML y luego lo envía a STDOUT. La entrada es nominalmente UTF-8, pero a veces se ha insertado basura. Necesito desinfectar la salida de modo que no se emitan octetos UTF-8 inválidos, de lo contrario, el consumidor descendente (Sphinx) explotará.
Por lo menos, me gustaría saber si los datos son inválidos, así que puedo evitar transmitirlos; idealmente podría eliminar solo los bytes ofensivos. Sin embargo, habilitar todos los fatalismos que puedo encontrar no me lleva allí con Perl 5.12 (FWIW, use v5.12; use warnings qw( FATAL utf8 );
está en efecto).
Estoy teniendo problemas específicamente con la secuencia "/xFE/xBF/xBE"
. Si creo un archivo que contenga solo estos tres bytes ( perl -e ''print "/xEF/xBF/xBE"'' > bad.txt
), intente leer el archivo con mode :encoding(UTF-8)
errors out with utf8 "/xFFFE" does not map to Unicode
, pero solo bajo 5.14.0. 5.12.3 y anterior son perfectamente buenas lecturas y más tarde escribir esa secuencia. No estoy seguro de dónde está obteniendo el /xFFFE
(BOM inversa inverso), pero al menos tener una queja es consistente con Sphinx.
Desafortunadamente, decode_utf8("/xEF/xBF/xBE", 1)
no causa errores debajo de 5.12 o 5.14. Preferiría un método de detección que no requiriera una capa de E / S codificada, ya que eso me dejará un mensaje de error y no habrá manera de desinfectar los octetos sin formato.
Estoy seguro de que hay más secuencias que debo abordar, pero solo manejar esto sería un comienzo. Entonces mis preguntas son: ¿puedo detectar de manera confiable este tipo de datos problemáticos con un perl antes de 5.14? ¿Qué rutina de sustitución generalmente puede desinfectar casi-UTF-8 en estricto UTF-8?
Deberías leer la sección UTF-8 vs. utf8 vs. UTF8 de los documentos de Encode .
Para resumir, Perl tiene dos codificaciones UTF-8 diferentes. Su codificación nativa se llama utf8
, y básicamente permite cualquier punto de código, independientemente de lo que dice el estándar Unicode sobre ese punto de código.
La otra codificación se llama utf-8
(también conocida como utf-8-strict
). Esto permite solo los puntos de código que se enumeran como legales para el intercambio por el estándar Unicode.
"/xEF/xBF/xBE"
, cuando se interpreta como UTF-8, decodifica al punto de código U+FFFE . Pero eso no es legal para el intercambio de acuerdo con Unicode, por lo que los programas que son estrictos sobre tales cosas se quejan.
En lugar de usar decode_utf8
(que usa la codificación lax utf8
), use la decode
con la codificación utf-8
. Y lea la sección Manejo de Datos Malformados para ver las diferentes formas en que puede manejar o quejarse de problemas.
Actualización: parece que algunas versiones de Perl no se quejan de U + FFFE, incluso cuando usan la codificación utf-8-strict
. Esto parece ser un error. Puede que tenga que crear una lista de puntos de código de los que se queja Sphinx y filtrarlos manualmente (por ejemplo, con tr
).
Tienes una cadena utf8 que contiene algunos utf8 no válidos ...
Esto lo reemplaza con un ''char malo'' predeterminado.
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);