質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.38%

  • Ruby

    9924questions

    Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

  • Ruby on Rails 4

    2562questions

    Ruby on Rails4はRubyによって書かれたオープンソースのウェブフレームワークです。 Ruby on Railsは「設定より規約」の原則に従っており、効率的に作業を行うために再開発を行う必要をなくしてくれます。

railsにてyamlファイルを出力する際に、yamlファイルの中身に日本語が含まれている場合

受付中

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 2,985

domingojapan

score 7

前提・実現したいこと

ruby単体で動作確認した処理をrailsでも動作するようにlibフォルダに移植しています。
最終的に所定のフォルダに所定のファイル名のyamlファイルを保存する処理になります。

該当のソースコード

//今後出力ファイルに出力するyaml_fileに値をセットする
def setting_dates(inputdates)
yaml_file = {
'timestamp' => inputdates[0],
'value' =>  inputdates[1],
'color' => inputdates[2],

end

//yamlファイルを出力
def output_yaml_file
open('sample_output.yml', 'w') do |e|
YAML.dump(yaml_file , e)
end
end

//method_hogehogeにて、setting_datesメソッドの引数inputdatesにセットするデータを作成し、返す。
//method_hogehogeの処理の中身は割愛する
//配列inputdatesの各要素にはいずれも文字列が入ります。
inputdates = method_hogehoge  
setting_dates(inputdates)  
output_yaml_file

発生している問題・エラーメッセージ

配列inputdatesに格納されているデータ(inputdates[0]/[1]/[2]各々)に日本語の文字列が一切含まれていなければ
エラーが発生する事なくsample_output.ymlが生成されます。生成されたymlの中身も狙い通りです。
ですが、データ(inputdates[0]/[1]/[2])のいずれかに日本語の文字列が含まれていれば
コマンドプロンプト上に
Encoding::UndefinedConversionError ("\xE3" from ASCII-8BIT to UTF-8):
が表示され、エラーとなります。YAML.dumpの箇所です。

試したこと

上記output_yaml_fileメソッド内の
open('sample_output.yml', 'w') do |e|
を  
open('sample_output.yml', 'wb') 
にすると、日本語の文字列が含まれていても。
エラーが発生する事なくsample_output.ymlが生成されます。
sample_output.ymlをテキストエディタで開いても、中身は狙い通りの文字列が入っていました。
日本語の文字も文字化けはしていませんでした。

確認したい事

Railsだと日本語文字列がバイナリ扱いされるなどの理由で今回の問題が発生していると考えているのですが、あっていますでしょうか?

あっている場合、対策を教えていただければ幸いです。
(試したことに記述したように"wb"でバイナリにすればyamlファイルは生成されるのですが、中身は本当に文字列だけのテキストなのでバイナリというのもなぁという感覚があります)

補足情報(言語/FW/ツール等のバージョンなど)

OSはWindows7 64bit
Rubyは2.2.5
Railsは4.2.1
エディタはatomで文字コードはrubyではスタンダードのUTF-8にしています。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

0

バイナリと言うよりも、inputdates[0]/[1]/[2]それぞれのエンコードがASCII-8BITとして設定されていることが問題と思われます。inputdates[0].encodingなどで、文字コード確認してみてください。たぶん、ASCII-8BITとなっています。

どうしてエラーになるのか

Rubyでは全てのString(文字列)について、文字コードが設定されています。たとえ、内部が同じバイト列であっても、どのような文字コードとして設定しているかによって、その意味が異なります。

# String.new時にエンコード指定はRuby2.3から使えます。Ruby2.3.0以上で試してください。
p String.new([0xE3, 0x81, 0x82, 0xE4, 0xBA, 0x9C].pack("C*"), encoding: Encoding::UTF_8)
p String.new([0xE3, 0x81, 0x82, 0xE4, 0xBA, 0x9C].pack("C*"), encoding: Encoding::ASCII_8BIT)

前者は"あ亜"とUTF-8の文字として認識してくれますが、後者は"\xE3\x81\x82\xE4\xBA\x9C"というただのバイトの並びとして認識しており、この二つは異なる文字列として扱っています。同じバイト列だからといって、ASCII-8BITからUTF-8に変換しようとしても、RubyはASCII部分(0x00-0x7f)まではASCII-8BITとUTF-8が同じであることは知っていますが、それ以外(0x80-0xff)の部分はどう解釈して良いかわかりません。そのため、そのまま変換しようとした場合はエラーになります。

この文字コードを意識する動きはファイルの読み書きの時も同じです。UTF-8として開いたファイルはUTF-8として読み書きされます※1。もし、UTF-8のファイルへ、UTF-8ではないEUC-JPの文字コードのStringを書き込もうとした場合、RubyはUTF-8に変換してから書き込みます。YAML.dumpでも同様な動きするため、ASCII-8BITの文字列をUTF-8に変換しようとしますが、上で書いた理由により変換に失敗します※2。

※1 ファイルを比較時のデフォルト文字コードはEncodinge.default_externalの値になります。通常Encodinge.default_externalは実行されたOSの環境に従い、Windowsでは通常Windows-31Jです。しかし、Railsなどのアプリではあらゆる環境で動作するようにしたい場合は、文字コードを指定しておく場合があります。今回は、どこかで既に指定しているはずです。

※2 YAML.dumpでASCII-8BITはバイナリ値に変換される場合もあるようです。

どうすればいいのか

いくつか方法があります。

  1. inputdates[0]/[1]/[2]を初めからUTF-8として認識させる。(推奨)
    どこから取り出したデータかわかりませんが、そのデータをRubyの文字列として認識させる段階でUTF-8に設定しておきます。データベースから取っている場合などは文字コードを指定しないとASCII-8BITになるので注意してください。
    日本語を使用する場合は、全ての文字列をUTF-8として認識させることを推奨します。ASCII-8BITのままですと、正規表現の処理やリテラルな文字列(別途UTF-8になっているはず)の結合のときに同じようなエラーが発生したり、意図せぬ動作をします。inputdatesの読み込み部分を見直してください。
  2. YAML用データを作るときに、強制的に変換させる。
    YAML用データを作るときに、inputdates[0].encode(Encoding::UTF_8, Encoding::UTF_8)等として、UTF-8で認識させたものをUTF-8の文字列として生成します。かなり強引な方法です。また、不正なUTF-8の場合はデフォルトだとエラーになりますので、不正な場合はどうするかなどオプションを追加してください。(詳しくはリファレンスを読んでください)
  3. ASCII-8BITとしてファイルを開く。(未検証)
    うまくいくかどうかわかりませんが、open('sample_output.yml', 'w:ASCII-8BIT')としてファイルの方を合わせてしまいます。'wb'と似たような動作になるはずです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.38%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • Ruby

    9924questions

    Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

  • Ruby on Rails 4

    2562questions

    Ruby on Rails4はRubyによって書かれたオープンソースのウェブフレームワークです。 Ruby on Railsは「設定より規約」の原則に従っており、効率的に作業を行うために再開発を行う必要をなくしてくれます。