gresreg

#!ruby -Ks
require "optparse"

# エラーメッセージを表示して終了する
def disp_error_exit( str)
  $stderr.puts str
  exit(2)
end

# fnameを上書きする
def save_file( fname, strs)
  tmpname = fname + '.tmp'
  bakname = fname + '.bak'

  open( tmpname, 'w') {|f| f.write( strs)}

  # TODO: baknameというファイルが存在したら,強制的に削除する?
  File.rename( fname, bakname)
  File.rename( tmpname, fname)
  File.delete( bakname)
end


# 引数のチェック
OptionParser.new {|opt|
  OPTS = {}
  begin
    opt.on('-e パターン', '正規表現を指定') {|v| 
      begin
        v = Regexp.new(v)
      rescue => err
        disp_error_exit( "error: '#{v}'は正しい正規表現ではない")
      end
      OPTS[:pat] ||= []
      OPTS[:pat] << v
    }
    opt.on('-g 文字列', '文字列を指定') {|v| 
      if OPTS[:str]
        disp_error_exit( "'#{v}'は無視されます")
      else
        OPTS[:str] = v
      end
    }
    opt.parse!(ARGV)
  rescue => err
    disp_error_exit( err.message )
  end
}

disp_error_exit( "error: ファイルが指定されていない") if (ARGV.size<=0)
disp_error_exit( "error: パターンが指定されていない") unless OPTS[:pat]
disp_error_exit( "error: 文字列が指定されていない") unless OPTS[:str]


# 改行を受け付ける.
# TODO: 他のエスケープシーケンスも処理する必要があるかも?
#OPTS[:str].gsub!(/\\n/,"\n")
#OPTS[:str].gsub!(/\\t/,"\t")
OPTS[:str].gsub!(/\\./) {|x|
  x = "\n" if x=="\\n"
  x = "\t" if x=="\\t"
  x
}


flag_found = false
begin
  flag_changed = false
  temp = []
  fname = nil

  ARGF.each {|l|
    if fname != ARGF.filename
      save_file(fname, temp) if flag_changed
      flag_changed = false
      fname = ARGF.filename
      temp = []
    end
    OPTS[:pat].each {|x|
      if x =~ l
        # puts "#{ARGF.filename} #{ARGF.file.lineno}:#{l}"
        l.gsub!( x, OPTS[:str])
        flag_changed = true
        flag_found = true
        break
      end
    }
    temp << l
  }

  save_file(fname, temp) if flag_changed

rescue => err
  disp_error_exit( err.message )
end

# 1つでも見つかったら0を,見つからない場合は1を返す
exit (flag_found)? 0: 1

使い方:
ruby gresreg.rb test/*.txt -e "(def|end)" -g "[\1]"
defかendを見つけたら,[def],[end]に置き換える

なぜ複数の正規表現を受け付けるようにしたのか?….コピペした元ソースが複数の引数を受け付けるやつだったからかも.


gresregというよりrubyの使い方.自分用にメモ:

>rem サブディレクトリの下も置換する
>ruby gresreg.rb **/*.txt -e abc -g ABC

>rem _で始まるファイルは無視する
>rem ""で囲まないと^が無くなる?
>ruby gresreg.rb "[^_]*.txt" -e abc -g ABC

>ruby gresreg.rb [!_]*.txt -e abc -g ABC
>rem でも可


追記 20070709 エスケープシーケンスの扱いを修正