いわゆる文字コード変換。

文字エンコーディングがEUC-JPのファイルを読み込んで、UTF-8とShift_JISで標準出力とファイルへ出力するサンプルを書いてみた。

1.8系では Iconv.conv を使用。
1.9系では String#encode や File.open の第二引数にエンコーディングを指定することで対応。

以下は、読み込むファイル eucjp_sample.txt の中身 (文字エンコーディングは EUC-JP)。


Hello, my friend.
きみに恋したNATSUがあったね。

変換サンプルのソースコード。


#!/usr/bin/env ruby
# coding: UTF-8
 
# String#encode が存在するかどうかで判断
if ''.respond_to?(:encode)
 
  # Ruby 1.9系
  def utf8_to_shift_jis(str)
    str.encode('Shift_JIS')
  end
 
  def read_eucjp_file(path)
    File.open(path, "r:EUC-JP:UTF-8").read()
  end
 
  def write_shiftjis_file(path, str)
    File.open(path, "w:Shift_JIS:UTF-8"){|f|f.write(str)}
  end
 
else
 
  # Ruby 1.8系
  $KCODE = 'UTF-8'
  require 'iconv'
 
  def utf8_to_shift_jis(str)
    Iconv.conv('Shift_JIS', 'UTF-8', str)
  end
 
  def read_eucjp_file(path)
    Iconv.conv('UTF-8', 'EUC-JP', File.read(path))
  end
 
  def write_shiftjis_file(path, str)
    File.open(path, "w:Shift_JIS:UTF-8"){|f|f.write(utf8_to_shift_jis(str))}
  end
 
end
 
# EUC-JPのファイルを読み込む
text = read_eucjp_file('eucjp_sample.txt')
 
# UTF-8で出力
puts '[UTF-8]'
puts text
 
# Shift_JISで出力
puts '[Shift_JIS]'
puts utf8_to_shift_jis(text)
 
# UTF-8のファイルを出力
File.open('utf8_sample.txt', 'w'){|f| f.write(text)}
 
# Shift_JISのファイルを出力
write_shiftjis_file('shiftjis_sample.txt', text)

Mac OS X (MacBook Air) + Ruby 1.8 で実行した結果。
UTF-8の環境なのでShift_JISの標準出力は文字化けしている。


$ uname -mrsv
Darwin 10.7.0 Darwin Kernel Version 10.7.0: Sat Jan 29 15:17:16 PST 2011; root:xnu-1504.9.37~1/RELEASE_I386 i386
 
$ env | grep LANG
LANG=ja_JP.UTF-8
 
$ ruby -v
ruby 1.8.7 (2009-06-12 patchlevel 174) [universal-darwin10.0]
 
$ ruby ./encode.rb 
[UTF-8]
Hello, my friend.
きみに恋したNATSUがあったね。
[Shift_JIS]
Hello, my friend.
???݂ɗ?????NATSU?????????ˁB

Windows XP + Ruby 1.9 で実行した結果。
Shift_JISの環境なのでUTF-8の標準出力は文字化けしている。


C:\hoge>uname -mrsv
WindowsNT 1 5 x86
 
C:\hoge>ver
 
Microsoft Windows XP [Version 5.1.2600]
 
C:\hoge>ruby -v
ruby 1.9.2p136 (2010-12-25) [i386-mingw32]
 
C:\hoge>ruby ./encode.rb
[UTF-8]
Hello, my friend.
縺阪∩縺ォ諱九@縺櫻ATSU縺後≠縺」縺溘・縲・
[Shift_JIS]
Hello, my friend.
きみに恋したNATSUがあったね。

両環境ともにちゃんと UTF-8 のファイル (utf8_sample.txt) と Shift_JIS のファイル (shiftjis_sample.txt) が生成されていた。

以下、リファレンスマニュアルから参考情報。

conv(to, from, str) -> String

与えられた文字コードにしたがって str を変換し、結果を文字列として返します。

Ruby 1.8.7 リファレンスマニュアル > singleton method Iconv.conv
String#encode メソッドは文字列のエンコーディングを変換した新しい文字列を生成して返します。 Ruby 1.9 ではこれを用いてエンコーディングを変換するのが標準的なやり方です。

Ruby 1.9.2 リファレンスマニュアル > 多言語化
第二引数のオープンモード・エンコーディング

文字列("mode" か "mode:ext_enc" か "mode:ext_enc:int_enc" という形式)か整数(File::Constants モジュールの定数の論理和)を組み合わせて指定します。

(中略)

エンコーディングの指定

ext_enc(外部エンコーディング)が指定されている場合、読み込まれた文字列にはこのエンコーディングが指定され、出力する文字列はそのエンコーディングに変換されます。

ext_encが'-bom'で終わる場合、その入力に含まれるBOMはあらかじめ削られます。また、BOMがあった場合、入力された文字列にはそのBOMに対応するエンコーディングが設定されます。

int_encも指定されていた場合、入力された文字列をext_encでエンコーディングされた文字列とみなしてint_encへと変換し、その結果にint_encを設定して返します。

Ruby 1.9.2 リファレンスマニュアル > module function Kernel.#open
$KCODE -> nil
$-K -> nil

この特殊変数は何の影響も持たなくなりました。

値を代入しても無視され、参照すると常に nil です。

Ruby 1.9.2 リファレンスマニュアル > Kernelモジュール > variable $-K
マジックコメントを使うことにより Ruby 実行系にスクリプトエンコーディングを伝えることができます。マジックコメントとはスクリプトファイルの1行目に書かれた

# coding: euc-jp

という形式のコメントのことです。1 行目が shebang である場合、マジックコメントは 2 行目に書くことができます(それ以降の行ではいけません。無視されます)。上の形式以外にも

# encoding: euc-jp
# -*- coding: euc-jp -*-
# vim:set fileencoding=euc-jp:

などの形式を解釈します。

#!/bin/sh
exec ruby19 -x "$0" "$@"
#!ruby
# coding: utf-8

このように -x オプションを使っている場合には「#! で始まり、ruby がある行」の次の行に書きます。

マジックコメントによりスクリプトファイル毎にスクリプトエンコーディングを指定することができます。あるファイルに非 ASCII 文字を使う場合、マジックコメントを必ず設定しなければいけません。設定されていなかった場合、エラーになります。

Ruby 1.9.2 リファレンスマニュアル > 多言語化 > magic comment

tags: ruby

Posted by NI-Lab. (@nilab)