2012年4月1日日曜日

文字コードの変換


文字コードの変換スクリプト。iconvが文字コードを判別してくれないから、RubyのKconvを使って自動判別と変換をしている。
#! /usr/bin/ruby
require 'kconv'
require 'optparse'
# option
def kname(str)
  str = str.upcase rescue ''
  if str =~ /^J/
    Kconv::JIS
  elsif str =~ /^S/
    Kconv::SJIS
  elsif str =~ /^E/
    Kconv::EUC
  elsif str =~ /^U.*16/
    Kconv::UTF16
  elsif str =~ /^U/
    Kconv::UTF8
  elsif str =~ /^A/
    Kconv::AUTO
  else
    nil
  end
end
option = {
  :from => 'auto',
  :to => nil,
  :lf => true
}
begin
  myname = File.basename($0).split(/\./)
  myname.shift
  option[:to] = myname.pop unless myname.empty?
  option[:from] = myname.pop unless myname.empty?
rescue
end
ARGV.options do |opt|
  opt.on('-f CODE', '--from CODE') do |v|
    option[:from] = v
  end
  opt.on('-t CODE', '--to CODE') do |v|
    option[:to] = v
  end
  opt.on('--crlf') do
    option[:lf] = false
  end
  opt.on('--lf') do
    option[:lf] = true
  end
  opt.parse!
end
option[:from] = kname(option[:from])
option[:to] = kname(option[:to])
raise "invalid option(s)" unless option[:from] and option[:to]
# main
ARGV.each do |filename|
  result = 'done'
  begin
    ctx = File.read(filename)
    File.open(filename, 'w') do |f|
      ctx = ctx.kconv(option[:to], option[:from])
      ctx.gsub!("\r", '') if option[:lf]
      f.write(ctx)
    end
  rescue
    result = 'failed'
  end
  $stderr.print("#{filename} : #{result}\n")
end
これをパスの通ったところにj2jという名前で置いて、例えば
% j2j -tu foo.txt bar.txt
と実行すれば、foo.txtとbar.txtをUTF-8に変換する。複数ファイルを入力する場合、入力ファイルの文字コードはバラバラでもOK。フィルタではなく指定ファイルを直接変更するので注意。
おまけ機能。実行スクリプトの名前のサフィックスで-tオプションのデフォルト値を指定できる。例えばj2j.sjisという名前のシンボリックリンクを作っておけば
% j2j.sjis baz.txt
でbaz.txtをShift_JISに変換できる。

いい加減、コードのコピペはやめたいなー。どこかコード置き場を借りようかな。

0 件のコメント:

コメントを投稿