Estou escrevendo um rastreador em Ruby (1.9) que consome muito HTML de muitos sites aleatórios.
Ao tentar extrair links, decidi usar apenas .scan(/href="(.*?)"/i)
nokogiri / hpricot (maior aceleração). O problema é que agora recebo muitos invalid byte sequence in UTF-8
erros " ".
Pelo que entendi, a net/http
biblioteca não tem opções específicas de codificação e o material que vem basicamente não está devidamente marcado.
Qual seria a melhor maneira de realmente trabalhar com os dados recebidos? Tentei .encode
com o conjunto de opções substituir e inválido, mas sem sucesso até agora ...
109
'U*'
desfaz'C*'
?Respostas:
No Ruby 1.9.3, é possível usar String.encode para "ignorar" as sequências UTF-8 inválidas. Aqui está um snippet que funcionará em 1.8 ( iconv ) e 1.9 ( String # encode ):
ou se você tiver realmente problemas de entrada, pode fazer uma conversão dupla de UTF-8 para UTF-16 e de volta para UTF-8:
fonte
file_contents.encode!('UTF-16', 'UTF-8', :invalid => :replace, :replace => '')
file_contents.encode!('UTF-8', 'UTF-16')
force_encoding
. Se você leu um ISO8859-1 como um UTF-8 (e, portanto, essa string contém UTF-8 inválido), então você pode "reinterpretar" como ISO8859-1 com the_string.force_encoding ("ISO8859-1") e apenas trabalhar com essa string em sua codificação real..encode('UTF-8')
é um ambiente autônomo e nenhuma verificação é executada. Documentação do núcleo do Ruby para codificação . No entanto, convertê-lo em UTF-16 primeiro força a execução de todas as verificações de sequências de bytes inválidas e as substituições são feitas conforme necessário.A resposta aceita nem a outra resposta funcionam para mim. Eu encontrei esta postagem que sugeria
Isso resolveu o problema para mim.
fonte
Minha solução atual é executar:
Isso vai pelo menos me livrar das exceções que eram o meu principal problema
fonte
valid_encoding?
que parece detectar quando algo está errado.val.unpack('C*').pack('U*') if !val.valid_encoding?
.\xB0
costas em símbolos de graus. Mesmo avalid_encoding?
volta verdade, mas eu ainda verificar se isso não acontecer e retirar os personagens ofender usando a resposta de Amir acima:string.encode!('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '')
. Eu também tentei aforce_encoding
rota, mas falhou.Experimente isto:
fonte
Eu recomendo que você use um analisador HTML. Basta encontrar o mais rápido.
Analisar HTML não é tão fácil quanto pode parecer.
Os navegadores analisam sequências UTF-8 inválidas, em documentos HTML UTF-8, apenas colocando o símbolo " ". Portanto, uma vez que a sequência UTF-8 inválida no HTML é analisada, o texto resultante é uma string válida.
Mesmo dentro dos valores de atributo, você deve decodificar entidades HTML como amp
Esta é uma grande pergunta que resume por que você não pode analisar HTML de forma confiável com uma expressão regular: RegEx corresponde a tags abertas, exceto tags XHTML independentes
fonte
Isso parece funcionar:
fonte
fonte
Eu encontrei string, que tinha combinações de inglês, russo e alguns outros alfabetos, o que causou exceção. Preciso apenas de russo e inglês, e isso atualmente funciona para mim:
fonte
Embora a solução de Nakilon funcione, pelo menos no que diz respeito a superar o erro, no meu caso, eu tinha esse caractere estranho f-ed up originário do Microsoft Excel convertido para CSV que estava sendo registrado em ruby como um (veja só) cirílico K que em ruby era um K. em negrito. Para corrigir isso, usei 'iso-8859-1' viz.
CSV.parse(f, :encoding => "iso-8859-1")
, que transformou meu K cirílico esquisito em muito mais gerenciável/\xCA/
, que eu poderia remover comstring.gsub!(/\xCA/, '')
fonte
Antes de usar
scan
, certifique-se de que oContent-Type
cabeçalho da página solicitada sejatext/html
, uma vez que pode haver links para coisas como imagens que não estão codificadas em UTF-8. A página também pode ser não-html se você selecionar umhref
em algo como um<link>
elemento. A forma de verificar isso varia de acordo com a biblioteca HTTP que você está usando. Em seguida, certifique-se de que o resultado seja apenas ascii comString#ascii_only?
(não UTF-8 porque o HTML deve usar apenas ascii, as entidades podem ser usadas de outra forma). Se ambos os testes passarem, é seguro usarscan
.fonte
Se você não "se importa" com os dados, pode simplesmente fazer algo como:
search_params = params[:search].valid_encoding? ? params[:search].gsub(/\W+/, '') : "nothing"
Eu costumava
valid_encoding?
passar por ele. O meu é um campo de busca, então eu estava encontrando a mesma estranheza repetidamente, então usei algo como: apenas para que o sistema não quebrasse. Como eu não controlo a experiência do usuário para autovalidar antes de enviar essas informações (como feedback automático para dizer "simulado!"), Posso simplesmente pegar, retirar e retornar resultados em branco.fonte