« Railsで簡易カレンダ | トップページ | 複数ファイルのファイル名変更 »

2008年2月 7日 (木)

rubyで複数ファイルの文字列置換

単一ファイルの文字列の置き換えは簡単にエディタ(VIM)でできるんですが、複数のファイルだった時にいつも面倒だなーと思っていたので、rubyで作ってみました。

使い方

replace.rb [option] 変換対象正規表現文字列(//はつけない) 変換する文字列  ファイル名[ファイル名...]

オプション

-c      各変換に対して、変換前に変換していいかを尋ねる。(y/n/a/q)

-i       変換対象正規表現文字列の大文字、小文字を区別しない。

-m     複数行対応(”.”にCR/LF文字を含める。)

-h      ヘルプメッセージを出力して終了

-b      バックアップファイルの拡張子を指定(デフォルトは.bef) もし、-bのみで拡張子を指定しなかった場合はバックアップを行なわない。

(例)拡張子が.rbのファイルの/usr/local/bin/rubyを/usr/bin/rubyに変換する場合

find . -name '*.rb' |xargs ./replace.rb /usr/local/bin/ruby /usr/bin/ruby

無保証です。使用に問題があっても、責任をとりません。

replace.rb

 #!/usr/bin/ruby
require "optparse"

$opt_confirm = false
$opt_ignore_case = false
$opt_multi_case = false
$opt_ext = ".bef"
def write_data(file,orig,data)
  if orig == data
    return
  end
  if $opt_ext
    File.open(file+$opt_ext,"w") do |f|
      f.write(orig)
    end
    $stdout.puts "backup #{file} to #{file+$opt_ext}"
  end
  File.open(file,"w") do |f|
    f.write(data)
  end
  $stdout.puts "renewal #{file}"
end

 
begin
  parser = OptionParser.new do |opt|
   opt.banner = "Usage: #{File.basename($0)} Source(Type:RegularExpression) Destination(Type:String) File [File]..."
   opt.on("-c","--confirm","confirm y/n per replace") {|o|
      $opt_confirm=true
    }
    opt.on("-i","--ignorecase","ignore case for replace") {|o|
      $opt_ignore_case=true
    }
    opt.on("-m","--multiline",'"." muches CR/LF') {|o|
      $opt_multi_case=true
    }
    opt.on("-h","--help","print this message and quit") {|o|
      puts opt.help
      exit 0
    }
    opt.on("-b","--backup [EXT]",String,'extension backup file(default .bef) if you need not backup,use -b only') {|o|
      $opt_ext = o
    }
    opt.parse!(ARGV)
  end
rescue OptionParser::ParseError => err
  $stderr.puts err.message
  $stderr.puts parser.help
  exit 1
end
if ARGV[0] == ""
  ARGV.shift
end
if ARGV.length < 2
  $stderr.puts parser.help
  exit 1
end
opt=0
if $opt_ignore_case
  opt = Regexp::IGNORECASE
end
if $opt_multi_case
  opt += Regexp::MULTILINE
end
if opt == 0
  orig = Regexp.new(ARGV.shift)
else
  orig = Regexp.new(ARGV.shift,opt)
end

dest = ARGV.shift

ARGV.each do |file|
  unless File.file?(file)
    $stdout.puts "no exist #{file}"
    next
  end

  lines = nil
  orig_lines = ""
  File.open(file,"r") do |f|
    orig_lines = f.read
  end
  newlines=""
  lines = orig_lines
  unless $opt_confirm
    newlines = lines.gsub(orig,dest)
    write_data(file,orig_lines,newlines)
    next
  end

  while lines && orig.match(lines)
    bef_str = $`
    after_str = $'
    match_str = $&
    if $opt_multi_case
      $stdout.write "#{file} replace #{match_str} to #{dest} y/n/q/a ?"
    else
      sPos = lines.rindex("\n",$~.begin(0))
      if sPos == nil
        sPos = 0
      else
        sPos += 1
      end
      ePos = lines.index("\n",$~.end(0))
      line = lines[sPos...ePos]
      $stdout.write "#{file}:#{line} replace #{match_str} to #{dest} y/n/q/a ?"
    end
    case $stdin.gets
    when /q/i
      newlines += lines
      write_data(file,orig_lines,newlines)
      exit
    when /n/i
      newlines += bef_str
      newlines += match_str
      lines = after_str
      next
    when /a/i
      $opt_confirm = nil
      newlines += lines.gsub(orig,dest)
      break
    else
      newlines += bef_str
      newlines += dest
      lines = after_str
    end
  end
  if $opt_confirm
    newlines += lines if lines
  end
  write_data(file,orig_lines,newlines)
end

|

« Railsで簡易カレンダ | トップページ | 複数ファイルのファイル名変更 »

ruby」カテゴリの記事

コメント

コメントを書く



(ウェブ上には掲載しません)




トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/68673/40039858

この記事へのトラックバック一覧です: rubyで複数ファイルの文字列置換:

« Railsで簡易カレンダ | トップページ | 複数ファイルのファイル名変更 »