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 エスケープシーケンスの扱いを修正