Shift_JISのファイルをencodeしても文字化けが解消しなかったので調べてみました。
結論、force_encodingは強制変換ではなく、エンコーディング情報(文字コードが何か)を変えるだけ。エンコーディング情報を正しくしないと、encodeも正しくできない。
File.read → encode
Shift_JISのファイルを用意して、読み込み
> body = File.read('/tmp/test_sjis.txt') => "\x83e\x83X\x83g\r\n"
UTF-8(LFも)に変換してみる →文字化け
> body.encode(Encoding::UTF_8, invalid: :replace, undef: :replace, universal_newline: true) => "�e�X�g\r\n"
encodingを確認する →UTF-8として扱われている
> body.encoding => #<Encoding:UTF-8>
force_encoding → encode
encodingをSJIS変更する
※force_encodingはencodingを強制的に変更する(強制的にencodeする訳ではない)
> body.force_encoding(Encoding::SJIS) => "\x{8365}\x{8358}\x{8367}\r\n" > body.encoding => #<Encoding:Windows-31J>
※EncodingのSJISとWindows_31Jは同じもの
→class Encoding (Ruby 3.1 リファレンスマニュアル)
UTF-8に変換 →OK(文字化け解消)
> body.encode(Encoding::UTF_8, invalid: :replace, undef: :replace, universal_newline: true) => "テスト\r\n"
文字コードが分からない場合
文字コードがShift_JISだと解っている場合は、force_encodingでエンコーディング情報をSJIS(Windows-31J)に直してからencodeすればOK
文字コードが分からない場合は、NKF.guessで推測すればOK
> require 'nkf' => true > encoding = NKF.guess(body) => #<Encoding:Shift_JIS> > body.force_encoding(encoding) => "\x{8365}\x{8358}\x{8367}\r\n" > body.encode(Encoding::UTF_8, invalid: :replace, undef: :replace, universal_newline: true) => "テスト\n"
Faradayの場合
Gemfile
gem 'faraday'
% bundle install % rails s
> response = Faraday.get('http://localhost:3000/') => #<Faraday::Response:0x000000012d9bd380 @on_complete_callbacks=[], @env=#<Faraday::Env @method=:get @url=#<URI::HTTP http://localhost:3000/> @request=#... > response.body.encoding => #<Encoding:UTF-8>
ヘッダの「Content-Type: text/html; charset=utf-8」とかを見てそう!
public/にShift_JISのファイルを用意して
> response = Faraday.get('http://localhost:3000/test_sjis.txt') => #<Faraday::Response:0x000000012f725850 @on_complete_callbacks=[], @env=#<Faraday::Env @method=:get @url=#<URI::HTTP http://localhost:3000/test_sjis.tx... > response.body.encoding => #<Encoding:ASCII-8BIT>
Content-Typeがないと、ASCII-8BITを返すので、同様にNKF.guessで推測して、force_encodingでエンコーディング情報を直してからencodeする必要がある。