Une histoire sur la conversion des codes de caractères de UTF-8 en Shift-jis en Ruby

Une histoire sur la conversion des codes de caractères de UTF-8 en Shift-jis en Ruby

On m'a demandé de définir le code de caractère par défaut de la chaîne de caractères sur Shift-jis lorsque je crache du CSV dans mon travail actuel.

Le code de caractère par défaut pour les chaînes de caractères Ruby est UTF-8, j'ai donc pensé qu'il serait possible de le réaliser en le convertissant simplement en Shift-jis lors de la décharge de CSV, mais j'étais accro à autre chose.

Certaines personnes peuvent aussi en être accro, je vais donc décrire la solution.

Emplacement de montage addictif

L'éjection CSV peut être implémentée relativement facilement en utilisant la méthode generate de la classe CSV de la bibliothèque Ruby.

Image de mise en œuvre ↓

require "csv"

text =<<-EOS
id,first name,last name,age
1,taro,tanaka,20
2,jiro,suzuki,18
3,ami,sato,19
4,yumi,adachi,21
EOS

csv = CSV.generate(text, headers: true) do |csv|
  csv.add_row(["5", "saburo", "kondo", "34"])
end

Référence de code: https://docs.ruby-lang.org/ja/latest/method/CSV/s/generate.html

Si vous souhaitez convertir en shift-jis, vous pouvez spécifier l'encodage de sortie à l'aide de la touche: encoding.

CSV.generate(text, headers: true, encoding: "SJIS")

Avec cette option, l'encodage de sortie est automatiquement converti de utf-8 en shift-jis.

Lorsque je l'ai implémenté ici, l'erreur suivante s'est produite pour une raison quelconque .....

incompatible character encodings: Windows-31J and UTF-8

Recherche de cause

Recherchez pourquoi vous obtenez une erreur de codage.

Suite à la recherche de la chaîne de caractères à l'origine d'une erreur, une erreur s'est produite dans la chaîne de caractères suivante.

"AAA−0001"

C'est une chaîne qui ne semble pas étrange, pourquoi est-ce une erreur?

Après un examen plus approfondi, il semble que la conversion des caractères suivants en shif-jis entraînera une erreur d'exception.

Code de caractère (UTF-8) lettre Remarques
U+00A2 ¢ Symbole du cent (devise)
U+00A3 £ Symbole de la livre (devise)
U+00AC ¬ PAS symbole
U+2016 Double vertical line
U+2212 Signe moins
U+301C Dash de vague

Référence: https://osa.hatenablog.com/entry/2014/08/21/113602

"AAA−0001"

Puisque cette chaîne contient - (signe moins), on suppose qu'une erreur d'exception s'est produite.

Solution

Je comprends la cause de l'erreur. Alors, comment le résolvez-vous?

Le moyen le plus simple est d'étendre la classe de chaînes en utilisant la classe ouverte de Ruby.

Ruby n'a aucune restriction sur l'héritage de classe. Même les classes de bibliothèque intégrées telles que la classe String et la classe Array peuvent être héritées pour définir leurs propres classes.

Ajoutez donc une méthode à la classe String pour éviter les exceptions lors de la conversion vers Windows-31J comme suit.

class String
  def sjisable
    str = self
    #Remplacez les caractères de la table de conversion par les caractères ci-dessous
    from_chr = "\u{301C 2212 00A2 00A3 00AC 2013 2014 2016 203E 00A0 00F8 203A}"
    to_chr   = "\u{FF5E FF0D FFE0 FFE1 FFE2 FF0D 2015 2225 FFE3 0020 03A6 3009}"
    str.tr!(from_chr, to_chr)
    #Des caractères illégaux ont fui de la table de conversion?Convertir puis revenir en UTF8 pour éviter de futures exceptions
    str = str.encode("Windows-31J","UTF-8",:invalid => :replace,:undef=>:replace).encode("UTF-8","Windows-31J")
  end
end

Référence du code: https://qiita.com/yugo-yamamoto/items/0c12488447cb8c2fc018

En exécutant cette méthode à l'endroit où une erreur d'exception se produit, l'erreur d'exception ne se produira pas.

"AAA−0001".sjisable

Si vous ne souhaitez pas utiliser de classe ouverte

Les classes ouvertes sont très puissantes et peuvent être utilisées pour améliorer l'efficacité du développement.

D'un autre côté, c'est bien d'ajouter une méthode unique à la classe standard Ruby, mais même si vous lisez le code, vous ne pouvez pas dire qui a défini la méthode où et dans quel but, mais plutôt améliorer l'efficacité du développement de toute l'équipe. Laisse tomber.

Un autre inconvénient possible est qu'une erreur se produit à un moment inattendu.

Ou est-ce la responsabilité de la classe String de changer le code de caractère en Shift_JIS pour certaines personnes, ou est-ce la responsabilité de la classe qui gère CSV car il est nécessaire lors de la conversion en CSV? Je pense qu'il y aura une question.

Donc, si vous n'utilisez pas la classe ouverte, il est préférable de créer quelque chose comme la classe CsvUtility, de consolider les procédures de gestion du CSV et de l'implémenter afin qu'il puisse être affiché sous la forme Shift_JIS ou UTF-8. Devenir.

référence

[Junichi Ito. Introduction à Ruby pour les professionnels Des spécifications du langage aux techniques de développement / débogage pilotées par les tests](https://www.amazon.co.jp/dp/B077Q8BXHC/ref=dp-kindle-redirect?_encoding = UTF8 & btkr = 1)

Recommended Posts

Une histoire sur la conversion des codes de caractères de UTF-8 en Shift-jis en Ruby
Passer de SQLite3 à PostgreSQL dans un nouveau projet Ruby on Rails
Histoire de changer d'emploi d'un pasteur chrétien (apprenti) à un ingénieur web
L'histoire de la rencontre d'un débordement arithmétique qui ne devrait pas être rencontré dans Ruby
Une histoire sur l'évolution des compétences du COBOL cultivé pendant 5 ans à la fin des années 20 à un langage Web
Une histoire sur le JDK à l'ère de Java 11
Une histoire très utile sur la classe Struct de Ruby
Histoire d'essayer de faire fonctionner le fichier JAVA
Comment démarrer un indice à partir d'un nombre arbitraire dans le traitement itératif Ruby
Une histoire d'essayer de s'entendre avec Mockito
Une histoire sur l'effort de décompiler les fichiers JAR
Une histoire sur la réduction de la consommation de mémoire à 1/100 avec find_in_batches
Expression régulière Ruby Extrait d'une chaîne de caractères spécifique vers une chaîne de caractères
De Java à Ruby !!
Comment changer une chaîne dans un tableau en un nombre dans Ruby
Une histoire sur une BeanNotOfRequiredTypeException qui s'est produite après l'application d'AOP au printemps
Comment afficher des graphiques dans Ruby on Rails (LazyHighChart)
Je veux créer un fichier Parquet même en Ruby
Appliquer le CSS à une vue spécifique dans Ruby on Rails
À propos de la distribution intelligente dans le rappel du fragment à l'activité dans Kotlin
Une histoire de malentendu sur l'utilisation du scanner Java (mémo)
À propos de la méthode de conversion d'une chaîne de caractères en entier / fraction (données de conversion) en Java
Multiplication dans un tableau Ruby
À propos des expressions régulières dans Ruby
J'ai essayé d'écrire du code comme une déclaration de type en Ruby
Une histoire sur la fabrication d'une calculatrice pour calculer le taux de monticule d'obus
L'histoire que Tomcat a souffert d'une erreur de timeout dans Eclipse
Comment obtenir et ajouter des données depuis Firebase Firestore dans Ruby
Comment penser la conception de classe (division) dans un système d'entreprise (1)
Une histoire sur l'exécution d'un programme qui copie des fichiers en Java à partir d'un fichier chauve-souris pour rendre le travail quotidien un peu plus efficace