ruby encoding utf-8

ruby 1.9: secuencia de bytes no válida en UTF-8



encoding (11)

Estoy escribiendo un rastreador en Ruby (1.9) que consume mucho HTML de muchos sitios aleatorios.
Al intentar extraer enlaces, decidí usar .scan(/href="(.*?)"/i) lugar de nokogiri / hpricot (aceleración mayor). El problema es que ahora recibo muchos errores de " invalid byte sequence in UTF-8 ".
Según lo que entendí, la biblioteca net/http no tiene ninguna opción específica de codificación y, básicamente, las cosas que entran no están correctamente etiquetadas.
¿Cuál sería la mejor manera de trabajar con los datos entrantes? Intenté .encode con el reemplazo y el conjunto de opciones no válidas, pero hasta ahora no hay éxito ...


Antes de utilizar el scan , asegúrese de que el encabezado Content-Type la página solicitada sea text/html , ya que puede haber enlaces a cosas como imágenes que no están codificadas en UTF-8. La página también podría ser no-html si recogió un href en algo así como un elemento <link> . Cómo comprobar esto varía en qué biblioteca HTTP está utilizando. Luego, asegúrese de que el resultado sea solo ascii con String#ascii_only? (No UTF-8 porque se supone que HTML solo usa ascii, las entidades se pueden usar de otra forma). Si ambas pruebas pasan, es seguro usar el scan .


En Ruby 1.9.3, es posible utilizar String.encode para "ignorar" las secuencias UTF-8 no válidas. Aquí hay un fragmento que funcionará tanto en 1.8 ( iconv ) como 1.9 ( String#encode ):

require ''iconv'' unless String.method_defined?(:encode) if String.method_defined?(:encode) file_contents.encode!(''UTF-8'', ''UTF-8'', :invalid => :replace) else ic = Iconv.new(''UTF-8'', ''UTF-8//IGNORE'') file_contents = ic.iconv(file_contents) end

o si tiene una entrada realmente problemática, puede hacer una doble conversión de UTF-8 a UTF-16 y de regreso a UTF-8:

require ''iconv'' unless String.method_defined?(:encode) if String.method_defined?(:encode) file_contents.encode!(''UTF-16'', ''UTF-8'', :invalid => :replace, :replace => '''') file_contents.encode!(''UTF-8'', ''UTF-16'') else ic = Iconv.new(''UTF-8'', ''UTF-8//IGNORE'') file_contents = ic.iconv(file_contents) end


Esto parece funcionar:

def sanitize_utf8(string) return nil if string.nil? return string if string.valid_encoding? string.chars.select { |c| c.valid_encoding? }.join end


La respuesta aceptada ni la otra respuesta funcionan para mí. Encontré esta publicación que sugería

string.encode!(''UTF-8'', ''binary'', invalid: :replace, undef: :replace, replace: '''')

Esto solucionó el problema para mí.


Me encontré con una cadena, que tenía mezclas de inglés, ruso y algunos otros alfabetos, lo que causó una excepción. Necesito solo ruso e inglés, y esto actualmente funciona para mí:

ec1 = Encoding::Converter.new "UTF-8","Windows-1251",:invalid=>:replace,:undef=>:replace,:replace=>"" ec2 = Encoding::Converter.new "Windows-1251","UTF-8",:invalid=>:replace,:undef=>:replace,:replace=>"" t = ec2.convert ec1.convert t


Mi solución actual es correr:

my_string.unpack("C*").pack("U*")

Esto al menos eliminará las excepciones que era mi principal problema


Prueba esto:

def to_utf8(str) str = str.force_encoding(''UTF-8'') return str if str.valid_encoding? str.encode("UTF-8", ''binary'', invalid: :replace, undef: :replace, replace: '''') end


Si bien la solución de Nakilon funciona, al menos en cuanto a superar el error, en mi caso, tuve este extraño carácter f-ed originario de Microsoft Excel convertido a CSV que se estaba registrando en ruby ​​como un (obtener esto) cirílico K que en ruby era una K. en negrita. Para arreglar esto usé ''iso-8859-1'' viz. CSV.parse(f, :encoding => "iso-8859-1") , que convirtió mis extravagantes Kyric cirílicas en una mucho más manejable //xCA/ , que luego pude eliminar con string.gsub!(//xCA/, '''')


Si no te "importan" los datos, puedes hacer algo como:

search_params = params[:search].valid_encoding? ? params[:search].gsub(//W+/, '''') : "nothing"

Acabo de usar valid_encoding? para pasarlo. El mío es un campo de búsqueda, y estaba encontrando la misma rareza una y otra vez, así que usé algo así como: solo para que el sistema no se rompa. Como no controlo la experiencia del usuario para autoverificar antes de enviar esta información (como la respuesta automática para decir "¡ficticio!"), Puedo tomarlo, quitarlo y devolver resultados en blanco.


Te recomiendo que uses un analizador HTML. Solo encuentra el más rápido.

El análisis de HTML no es tan fácil como parece.

Los navegadores analizan secuencias UTF-8 no válidas, en documentos HTML UTF-8, con solo colocar el símbolo " ". Entonces, una vez que se analiza la secuencia inválida UTF-8 en el HTML, el texto resultante es una cadena válida.

Incluso dentro de los valores de los atributos tienes que decodificar entidades HTML como un amplificador

Aquí hay una gran pregunta que resume por qué no se puede analizar de manera confiable HTML con una expresión regular: RegEx coincide con las etiquetas abiertas, excepto las etiquetas autocontenidas XHTML.


attachment = file.read begin # Try it as UTF-8 directly cleaned = attachment.dup.force_encoding(''UTF-8'') unless cleaned.valid_encoding? # Some of it might be old Windows code page cleaned = attachment.encode( ''UTF-8'', ''Windows-1252'' ) end attachment = cleaned rescue EncodingError # Force it to UTF-8, throwing out invalid bits attachment = attachment.force_encoding("ISO-8859-1").encode("utf-8", replace: nil) end