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

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

ただいまの
回答率

90.35%

  • Ruby

    8162questions

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

UTF-8 and Windows-31J (Encoding::CompatibilityError)が直せない

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 2,994
退会済みユーザー

退会済みユーザー

下記のファイルで蔵書のデータの登録を日本語でして蔵書のデータを表示をすると UTF-8 and Windows-31J (Encoding::CompatibilityError)が出てしまいます。コマンドプロンプトのフォントはMS ゴシックにしてあります。
print "書籍名: "
book_info.title = gets.chomp
print "著者名: "
book_info.author = gets.chomp

print "書籍名: "
book_info.title = gets.chomp.encode("UTF-8")
print "著者名: "
book_info.author = gets.chomp.encode("UTF-8")
にすれば動くのですが教本の通り(下記のファイル)に書けない理由を知りたいと思い質問しました。

# -*- coding: utf-8 -*-
require 'date'
class BookInfo
  def initialize( title, author, page, publish_date )
   @title = title
   @author = author
   @page = page
   @publish_date = publish_date
  end
  attr_accessor :title, :author, :page, :publish_date
  def to_csv( key )
    "#{key},#{@title},#{@author},#{@page},#{@publish_date}\n"
  end
  def to_s
    "#{@title},#{@author}, #{@page}, #{@publish_date}"
  end
  def toFormattedString( sep = "\n" )
    "書籍名: #{@title}#{sep}著者名: #{author}#{sep}ページ数: #{@page}ページ#{sep}発刊日: #{@publish_date}#{sep}"
  end
end

class BookInfoManager
  def initialize( filename )
    @csv_fname = filename
    @book_infos = {}
  end
  def setUp
    open(@csv_fname, "r:UTF-8") {|file|
      file.each {|line|
        key, title, author, page, pdate = line.chomp.split(',')
        @book_infos[ key ] =
          BookInfo.new(title, author , page.to_i, Date.strptime(pdate))
      }
    }
  end
  def addBookInfo
    book_info = BookInfo.new( "", "", 0, Date.new )
    print "\n"
    print "キー: "
    key = gets.chomp
    print "書籍名: "
    book_info.title = gets.chomp
    print "著者名: "
    book_info.author = gets.chomp
    print "ページ数: "
    book_info.page = gets.chomp.to_i
    print "発刊年: "
    year = gets.chomp.to_i
    print "発刊月: "
    month = gets.chomp.to_i
    print "発刊日: "
    day = gets.chomp.to_i
    book_info.publish_date = Date.new( year, month, day )
    @book_infos[key] = book_info
    puts book_info.publish_date
    puts @book_infos[key]
  end
  require 'pp'
  def listAllBookInfos
    puts "\n---------------------------"
    @book_infos.each { |key, info|
      print info.toFormattedString
    puts "\n---------------------------"
    }
  end
  def saveAllBookInfos
    open(@csv_fname, "w:UTF-8") {|file|
      @book_infos.each { |key, info|
        file.print( info.to_csv( key ))
      }
      puts "\nファイルへ保存しました"
    }
  end
  def run
    while true
        print "
1. 蔵書データの登録
2. 蔵書データの表示
8. 蔵書データをファイルへ保存
9. 終了
番号を選んでください(1,2,8,9) :"
        num = gets.chomp
        case
        when '1' == num
          addBookInfo
        when '2' == num
          listAllBookInfos
        when '8' == num
          saveAllBookInfos
        when '9' == num
          break;
        else
          puts line.encoding
        end
    end
  end
end

book_info_manager = BookInfoManager.new("book_info.csv")
book_info_manager.setUp
book_info_manager.run
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 3

checkベストアンサー

+2

Rubyでは異なった文字コードの文字列を連結することができません。
Atomをデフォルトの状態で使っているということなので
Atomで書いたプログラムの文字コードは「UTF-8」になります。
もし質問者様がWindowsを使われている場合は、コマンドプロンプトの
デフォルトの文字コードは「Shift-JIS」なのでコマンドプロンプトから
入力した文字列の文字コードは「Shift-JIS」になります。
上のプログラムは出力するときに「プログラムに書かれた文字列」を
入力された文字列にくっつけるということを行います。(例「書籍名:ももたろう」)
ここで「UTF-8」と「Windows-31J(=Shift-JIS)」という異なった
文字コードの文字列が連結されてエラーが発生します。
.encode(文字コード)をすることで文字コードを変更することが可能で
コマンドプロンプトから入力される文字列の文字コードを「UTF-8」にして
文字コードをそろえることで普通に動くようになります。
間違っていたら申し訳ないですがLinuxのコマンドプロンプトの
デフォルトの文字コードは「UTF-8」らしいので、その教本の作者様が
Linuxを使用されていてプログラムの文字コードも「UTF-8」の場合は
.encode(文字コード)で文字コードを「UTF-8」にそろえる必要が
ありません。

追記

#encoding : utf-8
puts "あなたが入力した文字は「#{gets.chomp.encode(__ENCODING__)}」ですね?"


KSwordOfHaste様とたぶん同じ結果になると思います。
__ENCODING__」はこのプログラムの文字コードを表します。
この場合は「#encoding : utf-8」としているので「__ENCODING__」は「UTF-8」
になります。
「#encoding : windows-31J」とすれば「__ENCODING__」は「Window-31J」
になります。
encode("UTF-8")という風に書いていると、プログラムの文字コードを変更したときに
「encodeの括弧の中身を全て変更しないといけない!!」ということになるかもしれません。
KSwordOfHasteがなさっているように、プログラムの文字コードでencodeするように
すれば、自動的にencodeの括弧の中身も変化するようになるので
プログラムの文字コードを変えても括弧の中身を書き換える必要がありません。
文字コードを変更するつもりがない場合はencode("UTF-8")でも大丈夫です。

参考
Encoding

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/01/11 21:09

    本ではWindowsですね。
    タイトルは作りながら学ぶRuby入門 第2版です。
    本に書いてあるコマンドプロンプトの設定にしたのですが残念です。
    今回はいい勉強になりました。
    ありがとうございます。

    キャンセル

  • 2017/01/11 22:35

    自分は「scriptEncoding="このスクリプト".encoding」なんて書きましたがh_aさんの回答から__ENCODING__を使えばよいことが分かりました。自分の方が勉強させてもらいましたw;

    キャンセル

  • 2017/01/11 22:37

    いえいえ私の文字コードで死にかけた経験が活かせてよかったです。

    キャンセル

  • 2017/01/11 22:59

    #encoding : utf-8
    def addBookInfo
    book_info = BookInfo.new( "", "", 0, Date.new )
    print "\n"
    print "キー: "
    key = gets.chomp
    print "書籍名: "
    book_info.title = gets.chomp.encode(__ENCODING__)
    print "著者名: "
    book_info.author = gets.chomp.encode(__ENCODING__)
    print "ページ数: "
    book_info.page = gets.chomp.to_i
    print "発刊年: "
    year = gets.chomp.to_i
    print "発刊月: "
    month = gets.chomp.to_i
    print "発刊日: "
    day = gets.chomp.to_i
    book_info.publish_date = Date.new( year, month, day )
    @book_infos[key] = book_info
    puts book_info.publish_date
    puts @book_infos[key]
    end
    こういうことですね!確かにエラーがでなくなりました。
    こちらだと修正が簡単にできますね。すごいです!
    ありがとうございます!

    キャンセル

  • 2017/01/11 23:14

    どうでもよいことですが、個人的にRubyの勉強にはDXrubyというライブラリがおすすめです。
    32bit版のRubyじゃないと使えませんが、ゲームが作れます。
    何より、画像が表示できるのでコマンドプロンプトの真っ黒な画面より楽し気です。
    公式サイト(http://dxruby.osdn.jp/)
    DXRuby 1.4.5 リファレンスマニュアル(http://mirichi.github.io/dxruby-doc/index.html)
    DXRubyで 0から作る「ブロック崩し」(http://blog.livedoor.jp/noanoa07/archives/2045851.html)

    キャンセル

  • 2017/01/11 23:20

    今やってる教本が終わったらやってみようと思います。
    おすすめ教材まで教えていただき感謝してます。

    キャンセル

  • 2017/01/11 23:29

    教本ではなく、ゲームを作るための道具という感じでしょうか。
    require"dxruby"
    Window.loop do
    end
    これだけでウィンドウが作れます。
    とっても簡単なのでまた機会があれば。

    キャンセル

  • 2017/01/11 23:37

    空目しました。すみません。

    キャンセル

+2

もしスクリプトがutf-8で記述されているのだとしたらその中の文字列リテラルのencodingはutf-8になっていると思います。Windows環境でgetsすると文字のencodingはWindows-31j(つまりMicrosoftのShift-JIS)になると思います。

エンコーディングが異なる文字列を連結したりするとこのエラーが起こるみたいですよ?

Encoding::CompatibilityErrorクラス 

jrubyの環境しかないのですがやってみるとencodingが異なってもASCII文字onlyの場合は連結できるようですが漢字などが含まれていると連結時にこのエラーになりました。


追記:
ruby初心者なので何がよい方法かはわかりませんが、例えば文字をgetsで外部から入力させる場合は環境によってencodingが変わるため、安全に取り扱うためにスクリプト(あるいは希望する特定のencoding)に合わせてやるのがよいのではないかと思いました。

scriptEncoding="このスクリプト".encoding
...
s=gets.chomp.encode(scriptEncoding)
"漢字の文字列"+s

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/01/11 21:17

    すみません。追記のコードをどのように扱えばいいかわかりません。
    回答ありがとうございます。
    いい勉強になりました。

    キャンセル

+1

教本では、文字コードはすべてutf-8になっているんでしょう。

p Encoding.default_external
p Encoding.default_internal


を実行するとどうなりますか?

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/01/11 21:19

    #<Encoding:Windows-31J>
    nil
    という結果が出ました。
    エンコードの調べ方を教えていただきありがとうございました。

    キャンセル

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

  • Ruby

    8162questions

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