ruby-robotの夢

cygwin-ruby,qgisの達人を目指す奮闘記

古いSJISのRubyをUTF8に変換する

背景

私はcygwin上でもrubyを使っている。
excelファイル等を扱うことも多く、従来は、-Ksで、SJIS環境でコーディングすることが多かった。
linuxで作業することもあるのだが、数年前-KuでUTF-8に統一するように転換し、
ライブラリもUTFに書き換えた。

ある時、cygwinの古い-Ksプログラムを動かそうとすると、ライブラリでエンコードエラーが出る。
当然だが、-Ksファイルから、外部のUTFスクリプトを読むと、エラーになる。

そこで、メインスクリプトSJISから、UTFに変換することとした。

SJIS⇒UTFで修正すべき点

①シェルラッパで、-Ksを、-Kuに
スクリプト文字コードを、sjisからutf-8
③入出力ファイルは、sjisのままにするため、入出力では、encoding:"SJIS:UTF-8" オプションを追加。

昔作ったスクリプトは数多いが、使うたびに、コード変換するのも面倒なので、
変換スクリプトを作った。

その他

※入出力は、様々な書き方があり、全てのケースに対応することは難しい。
私が多用するのは、File.open IO.readlines,CSV.read なので、これにのみ対応する。
※シェルラッパも、かつては、/usr/bin/ruby等を使っていたが、rbenvを使うようにしたことから、
/bin/bashを用いた方法に変えている。(こうしないと、古いrubyが起動して動かなくなる。)
※ファイルのmtimeは、変えたくないので、保存している。
nkfを用いてコード判定したが、rubyで読んで判定する方法もあるだろう。

rubyスクリプト

#!/bin/bash
exec ruby -S -x -Ku "$0" "$@" #s,u,e
#!ruby
$,="\t";$\="\n"
encs='encoding:"SJIS:UTF-8"' #encoding_string
ARGV.each{|argv|
  printf argv+"\t" 
 mtime=File.stat(argv).mtime
  nfo=argv+".utf"
  ans=`nkf -g #{argv}`.chomp
  heads=`head -2 #{argv} | nkf`.split($\)
  wbash='#!/bin/bash
exec ruby -S -x -Ku "$0" "$@"
#!ruby'
  wrubys=["#!/usr/bin/ruby -Ks","#!/bin/ruby -Ks"]
  wrapver=(heads[0][12]==wbash)?"bash":"ruby" if heads[0]
  head=( heads[0] and heads[0].match(/bash/) )?heads[1]:heads[0] 
 jhead=(head==nil)?"NO":(head.match(/-Ks/)?"SJIS":((head.match(/-Ku/))?"UTF8":"EUC"))
  if ans.match(/Shift_JIS/)
    print "SJIS",jhead,wrapver,head 
   contents=IO.readlines(argv,encoding:"SJIS:UTF-8",chomp:true) 
   ios=contents.select{|l| l.match(/(File\.open|IO\.readlines|CSV\.read)/)}
#   print ios
    subs=contents.map.with_index{|l,i|
      wrubys.each{|wruby| l.sub!(wruby,wbash)} if i==0 
     l.sub!(/ -Ks/," -Ku") if i==0 or i==1 
     if  m=l.match(/File\.open\((.*),"(r|w)"\)/)
        l.sub!(/File\.open\(.*\)/, "File.open(#{m[1]},\"#{m[2]}\",#{encs})") 
       print "  Fopen",l.sub(/^\t*/,"")
      elsif m=l.match(/IO\.readlines\((.*)\)/)
        l.sub!(/IO\.readlines\(.*\)/, "IO.readlines(#{m[1]},#{encs})")
        print "  Oread",l.sub(/^\t*/,"")
      elsif m=l.match(/CSV\.read\((.*)\)/)
        l.sub!(/CSV\.read\(.*\)/, "CSV.read(#{m[1]},#{encs})")
        print "  SVread",l.sub(/^\t*/,"")
      end
      l
    }
    File.write(nfo,subs*$\)
#   puts `nkf -u #{argv} | dos2ux | sed 1s/-Ks/-Ku/ > #{nfo}`
    File.utime(mtime,mtime,nfo)
    File.chmod(0755,nfo)
    puts `ls -o #{nfo}`
  elsif ans.match(/UTF/);print "UTF",head
  elsif ans.match(/EUC/);print "EUC",head
  else;print "OTHER!!!",ans
  end
}