古いSJISのRubyをUTF8に変換する
背景
私はcygwin上でもrubyを使っている。
excelファイル等を扱うことも多く、従来は、-Ksで、SJIS環境でコーディングすることが多かった。
linuxで作業することもあるのだが、数年前-KuでUTF-8に統一するように転換し、
ライブラリもUTFに書き換えた。
ある時、cygwinの古い-Ksプログラムを動かそうとすると、ライブラリでエンコードエラーが出る。
当然だが、-Ksファイルから、外部の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 }