web-dev-qa-db-fra.com

Convertir des caractères non-ASCII d'ASCII-8BIT en UTF-8

Je extrait du texte de sites distants et essaie de le charger dans une application Ruby 1.9/Rails 3 qui utilise par défaut utf-8.

Voici un exemple de texte offensant:

Cancer Res; 71(3); 1-11. ©2011 AACR.\n

Ce code de copyright développé ressemble à ceci:

Cancer Res; 71(3); 1-11. \xC2\xA92011 AACR.\n

Ruby me dit que la chaîne est codée au format ASCII-8BIT et que l'alimentation de mon application Rails me procure ceci:

incompatible character encodings: ASCII-8BIT and UTF-8

Je peux enlever le code de copyright en utilisant cette regex

str.gsub(/[\x00-\x7F]/n,'?')

pour produire ceci

Cancer Res; 71(3); 1-11. ??2011 AACR.\n

Mais comment puis-je obtenir un symbole de copyright (et divers autres symboles tels que des lettres grecques) converti en mêmes symboles dans UTF-8? C'est sûrement possible ...

Je vois des références à l'aide de force_encoding mais cela ne fonctionne pas:

str.force_encoding('utf-8').encode

Je me rends compte que beaucoup d'autres personnes ont des problèmes similaires, mais je n'ai pas encore trouvé de solution qui fonctionne.

40
craic.com

Cela fonctionne pour moi:

#encoding: ASCII-8BIT
str = "\xC2\xA92011 AACR"
p str, str.encoding
#=> "\xC2\xA92011 AACR"
#=> #<Encoding:ASCII-8BIT>

str.force_encoding('UTF-8')
p str, str.encoding
#=> "©2011 AACR"
#=> #<Encoding:UTF-8>
58
Phrogz

Il y a deux possibilités:

  1. Les données d'entrée sont déjà UTF-8, mais Ruby ne le sait tout simplement pas. Cela semble être votre cas, car "\ xC2\xA9" est valide en UTF-8 pour le symbole de copyright. Dans ce cas, vous devez simplement indiquer à Ruby que les données sont déjà au format UTF-8 avec force_encoding.

    Par exemple, "\ xC2\xA9" .force_encoding ('ASCII-8BIT') recréerait le bit pertinent de vos données d'entrée. Et "\ xC2\xA9" .force_encoding ('ASCII-8BIT'). Force_encoding ('UTF-8') montrerait que vous pouvez dire à Ruby qu'il s'agit bien de UTF-8 et obtenir le résultat souhaité.

  2. Les données d'entrée sont dans un autre encodage et vous avez besoin de Ruby pour les transcoder en UTF-8. Dans ce cas, vous devez dire à Ruby quel est le codage actuel (ASCII-8BIT est Ruby-parler pour binaire, ce n'est pas un vrai codage), puis dire à Ruby de le transcoder.

    Par exemple, supposons que vos données d'entrée soient ISO-8859-1. Dans cet encodage, le symbole de copyright est juste "\ xA9". Cela générerait un tel morceau de données: "\ xA9" .force_encoding ('ISO-8859-1'). Cela montrerait que vous pouvez faire en sorte que Ruby transcode cela en UTF-8: "\ xA9" .force_encoding ('ISO -8859-1 '). Encoder (' UTF-8 ')

27
Jason Heiss

J'avais l'habitude de faire cela pour un script qui grattait des pages codées en grec sous Windows, en utilisant open-uri, iconv et Hpricot:

doc = open(DATA_URL)
doc.rewind
data = Hpricot(Iconv.conv('utf-8', "WINDOWS-1253", doc.readlines.join("\n")))

Je crois que c'était Ruby 1.8.7, je ne sais pas comment les choses se passent avec Ruby 1.9

6
Achilles

J'ai eu des problèmes avec l'encodage des caractères et les autres réponses ont été utiles, mais n'ont pas fonctionné pour tous les cas. Voici la solution que j'ai proposée pour forcer le codage lorsque possible et le transcodage à l'aide de «? Voici la solution:

  def encode str
    encoded = str.force_encoding('UTF-8')
    unless encoded.valid_encoding?
      encoded = str.encode("utf-8", invalid: :replace, undef: :replace, replace: '?')
    end
    encoded
  end

force_encoding fonctionne la plupart du temps, mais j'ai rencontré des chaînes qui échouaient. Des chaînes comme celles-ci auront des caractères non valides remplacés:

 str = "don't panic: \xD3"
 str.valid_encoding?
 false
 str = str.encode("utf-8", invalid: :replace, undef: :replace, replace: '?')
 "don't panic: ?"
 str.valid_encoding?
 true
0
Jared Menard