J'écris un moteur de balayage dans Ruby (1.9) qui consomme beaucoup de HTML à partir de beaucoup de sites aléatoires.
En essayant d'extraire des liens, j'ai décidé d'utiliser .scan(/href="(.*?)"/i)
au lieu de nokogiri/hpricot (accélération majeure). Le problème est que je reçois maintenant beaucoup d'erreurs "invalid byte sequence in UTF-8
". D'après ce que j'ai compris, la bibliothèque net/http
n'a pas d'options spécifiques d'encodage et les éléments qui entrent dans la base ne sont pas correctement étiquetés.
Quelle serait la meilleure façon de travailler avec ces données entrantes? J'ai essayé .encode
le remplacer et les options invalides ensemble, mais sans succès jusqu'à présent ...ruby 1.9: séquence d'octets invalide dans UTF-8
Répondre
Avant d'utiliser scan
, assurez-vous que l'en-tête de page demandée est Content-Type
text/html
, car il peut y avoir des liens vers des choses comme des images qui sont pas encodé en UTF-8. La page pourrait également être non-html si vous avez ramassé un href
dans quelque chose comme un élément <link>
. Comment vérifier cela varie sur quelle bibliothèque HTTP vous utilisez. Ensuite, assurez-vous que le résultat est seulement ascii avec String#ascii_only?
(pas UTF-8 parce que le HTML est seulement supposé utiliser ascii, les entités peuvent être utilisées autrement). Si ces deux tests réussissent, vous pouvez utiliser scan
en toute sécurité.
merci, mais ce n'est pas mon problème :) J'extrais seulement la partie hôte de l'URL de toute façon et ne frappe que la première page. Mon problème est que mon entrée n'est apparemment pas UTF-8 et que le foo de l'encodage 1.9 ne fonctionne pas. –
@Marc Seeger: Que voulez-vous dire par "mon entrée"? Stdin, l'URL ou le corps de la page? – Adrian
HTML peut être codé en UTF-8: http://en.wikipedia.org/wiki/Character_encodings_in_HTML – Eduardo
Je vous recommande d'utiliser un analyseur HTML. Trouve juste le plus rapide.
L'analyse HTML n'est pas aussi simple que cela puisse paraître.
Les navigateurs analysent les séquences UTF-8 invalides, dans les documents HTML UTF-8, en mettant juste le symbole " ". Ainsi, une fois que la séquence UTF-8 invalide dans le code HTML est analysée, le texte résultant est une chaîne valide.
vous des valeurs d'attribut Même à l'intérieur devez décoder les entités HTML comme ici ampli
est une question qui résume pourquoi vous ne pouvez pas analyser de manière fiable HTML avec une expression régulière: RegEx match open tags except XHTML self-contained tags
J'aimerais garder l'expression rationnelle car elle est environ 10 fois plus rapide et je ne veux vraiment pas analyser le HTML correctement, mais je veux juste extraire les liens. Je devrais être en mesure de remplacer les parties invalides dans Ruby en faisant juste: ok_string = bad_string.encode ("UTF-8", {: invalide =>: remplacer,: undef =>: remplacer}) mais cela doesn ne semble pas fonctionner :( –
J'ai rencontré chaîne, qui avait des mélanges d'anglais, de russe et d'autres alphabets, ce qui a causé une exception. J'ai besoin que le russe et l'anglais, et cela fonctionne actuellement pour moi:
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
Ma solution actuelle consiste à exécuter:
my_string.unpack("C*").pack("U*")
Cela au moins se débarrasser des exceptions qui était mon principal problème
J'utilise cette méthode en combinaison avec «valid_encoding?» qui semble détecter quand quelque chose ne va pas. 'val.unpack ('C *'). pack ('U *') si! val.valid_encoding? '. –
Celui-ci a fonctionné pour moi et a réussi à convertir mes' \ xB0' en symboles degrés Même le 'valid_encoding?' revient vrai mais je vérifie toujours s'il ne le fait pas et dépouille les caractères offensants en utilisant La réponse d'Amir ci-dessus: 'string.encode! ('UTF-8', 'binary', invalide:: replace, undef:: replace, replace: '')'. J'avais aussi essayé la route 'force_encoding' mais ça a échoué. – hamstar
C'est génial, merci –
Dans Ruby 1.9.3, il est possible d'utiliser String.encode pour "ignorer" les séquences UTF-8 non valides. Voici un extrait qui fonctionne aussi bien dans 1,8 (iconv) et 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
ou si vous avez entrée vraiment gênants, vous pouvez faire une double conversion UTF-8 en UTF-16 et retour à 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
J'ai comparé avec ma solution et trouvé, que le mien perd quelques lettres, au moins 'ё':' "Alena V. \" '. Alors que votre solution le conserve: '" Ale \ u0308na V \ ". Agréable. – Nakilon
Avec une entrée problématique, j'utilise aussi une double conversion de UTF-8 à UTF-16 puis de nouveau à UTF-8 'file_contents.encode! ('UTF-16', 'UTF-8',: invalid =>: replace ,: replace => '') '' file_contents.encode! ('UTF-8', 'UTF-16') ' – ecerulm
Il y a aussi l'option' force_encoding'. Si vous avez lu un ISO8859-1 comme un UTF-8 (et donc cette chaîne contient un UTF-8 invalide) alors vous pouvez le "réinterpréter" comme ISO8859-1 avec the_string.force_encoding ("ISO8859-1") et juste travailler avec cette chaîne dans son encodage réel. – ecerulm
Alors que la solution de Nakilon fonctionne, au moins jusqu'à ce qu'ils aient passé l'erreur, dans mon cas, j'ai eu cette étrange caractère f-ed up provenant de Microsoft Excel converti au format CSV qui enregistrait en ruby comme un (obtenir ceci) K cyrillique qui dans ruby était un K. en gras Pour réparer cela j'ai utilisé 'iso-8859-1' à savoir.CSV.parse(f, :encoding => "iso-8859-1")
, qui a tourné mon Freaky Deaky cyrillique K de dans beaucoup plus facile à gérer /\xCA/
, que je pourrais alors enlever avec string.gsub!(/\xCA/, '')
Encore une fois, je veux juste noter que pendant que Nakilon (et d'autres) fixait les caractères cyrilliques provenant de (haha) Cyrillia, cette sortie est sortie standard pour un csv qui a été converti à partir de xls! –
Cela semble fonctionner:
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 réponse acceptée ni l'autre travail de réponse pour moi. J'ai trouvé this post qui a suggéré
string.encode!('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '')
Cela a résolu le problème pour moi.
Cela a résolu le problème pour moi et j'aime utiliser des méthodes non-obsolètes (j'ai maintenant Ruby 2.0). –
Celui-ci est le seul qui fonctionne! J'ai essayé toute la solution ci-dessus, aucun d'entre eux travaillent chaîne qui a utilisé dans le test "fdsfdsf dfsf SFD fs sdf
fooo??? {[email protected]#$%^&*()_+}
Si vous ne le faites pas « soins » sur les données que vous pouvez juste faire quelque chose comme:
search_params = params[:search].valid_encoding? ? params[:search].gsub(/\W+/, '') : "nothing"
Je viens d'utiliser valid_encoding?
pour obtenir passé il. Le mien est un champ de recherche, et donc je trouvais la même bizarrerie encore et encore alors j'ai utilisé quelque chose comme: juste pour que le système ne se casse pas. Puisque je ne contrôle pas l'expérience de l'utilisateur pour autovalidate avant d'envoyer cette information (comme rétroaction automatique pour dire "dummy up!") Je peux juste le prendre, dépouiller et renvoyer des résultats vierges.
Essayez ceci:
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
Meilleure réponse pour mon Cas! Merci – Aldo
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
- 1. Ruby 1.9 champ renvoyant l'encodage ASCII même si UTF8 spécifié
- 2. Ruby: séquence d'octets invalide en UTF-8
- 3. Ruby 1.9 - char multi-octets invalide (US-ASCII)
- 4. Ruby 1.9 -Ku, mem_cache_store et erreur d'échappement multi-octets invalide
- 5. Obtenir une "séquence d'octets invalide en US-ASCII" quand j'essaye de télécharger un fichier dans Ramaze et Ruby 1.9
- 6. Ruby 1.9 méthodes Ruby 1.8.6
- 7. Ruby 1.9 encodage regex
- 8. JRuby avec Ruby 1.9
- 9. Mongrel avec Ruby 1.9
- 10. Erreur Postgres sur insert - ERREUR: séquence d'octets invalide pour l'encodage "UTF8": 0x00
- 11. Ruby Pony alternative à Ruby 1.9?
- 12. Problème d'encodage Ruby UTF8
- 13. Comment générer un bytecode dans Ruby 1.9?
- 14. Variables d'instance incorporées dans Ruby 1.9?
- 15. Ruby 1.9 GarbageCollector, GC.disable/enable
- 16. joyau Fleximage sur Ruby 1.9
- 17. char multi-octets invalide (US-ASCII) avec Rails et Ruby 1.9
- 18. Ruby 1.9 Array.to_s se comporte différemment?
- 19. Pourquoi Ruby 1.9 permet le dépassement! ! =! ~?
- 20. Apprendre Ruby - Version 1.8 ou 1.9?
- 21. Ruby 1.9 compatible graphique de traçage/graphique?
- 22. Ruby 1.8 vs 1.9 - rejet destructeur! opérateur
- 23. Problème de codage JSON avec Ruby 1.9 et HTTParty
- 24. client de savon pour ruby 1.9 et rails
- 25. écrire csv dans ruby 1.9 et CSV :: Writer
- 26. Quelles sont les principales modifications de syntaxe dans Ruby 1.9?
- 27. Évitez l'objet object_id lorsque vous utilisez andand dans Ruby 1.9?
- 28. Erreur d'accès est survenue dans Ruby 1.9 + MySQL
- 29. Suivre la fuite de mémoire dans Ruby 1.9
- 30. ActiveRecord extrait les enregistrements en encodage ASCII dans Ruby 1.9
quelque chose qui pourrait briser les caractères, mais conserve la chaîne valable pour d'autres bibliothèques: valid_string = untrusted_string.unpack ('C *') paquet ('U *. ') –
Ayant le problème exact, essayé les mêmes solutions. Pas d'amour. J'ai essayé Marc, mais il semble tout brouiller. Êtes-vous sûr que '' U '' 'défait' 'C *' '? –
Non, ce n'est pas le cas :) Je l'ai juste utilisé dans un webcrawler où je m'intéresse à ce que les bibliothèques tierces ne se plantent pas plus que moi à propos d'une phrase ici et là. –