#!/usr/bin/env ruby # 文字コード、改行コードの変換、および、行末の空白の除去を行う Ruby スクリプト # # Yasunori Miyamoto # http://tipszone.jp/20140410_encode/ # mailto: nori@tipszone.jp Version = '2.1' Release = '2014-04-11' require 'optparse' require 'nkf' # default option params = {input_encoding: 'AUTO'} opt = OptionParser.new opt.program_name = File.basename(__FILE__) opt.version = Version opt.release = Release opt.banner = "Usage: #{opt.program_name} [options] [files]" opt.on("-i", "--input encoding", "Default: #{params[:input_encoding]}") {|v| params[:input_encoding] = v.upcase} opt.on("-o", "--output encoding") {|v| params[:output_encoding] = v.upcase} opt.separator " " opt.on("--crlf", "Line feed code") {|v| params[:line_feed] = :CRLF} opt.on("--cr") {|v| params[:line_feed] = :CR} opt.on("--lf") {|v| params[:line_feed] = :LF} opt.separator " " opt.on("-r", "--remove-trailing-spaces") {|v| params[:remove_trailing_spaces] = true} opt.parse!(ARGV) class String def binary? return false unless [NKF::ASCII, NKF::BINARY].include? NKF.guess(self) self.include?("\0") end end # 文字コードを変換する。 # Param: String str 処理対象の文字列 # Param: String|nil output_encoding 出力文字コード # Param: Encoding|String input_encoding ファイルからの入力文字コード # Return: bool ファイルから読み込んだ時の文字コードから変更されたかどうか def convert_encoding(str, output_encoding, input_encoding) str.encode!(output_encoding || input_encoding) if output_encoding && output_encoding != input_encoding.to_s.upcase puts " #{input_encoding} -> #{output_encoding}" return true end return false end # 改行コードを変更する。 # Param: String str 処理対象の文字列 # Param: String|nil line_feed 変換先の改行コードを表す文字列 ("LF" or "CRLF" or "CR") # Return: bool 変更の有無 def convert_line_feed(str, line_feed) if line_feed line_feed_code = {LF: "\n", CRLF: "\r\n", CR: "\r"}[line_feed] line_feed_changed = false str.gsub!(/\r\n|\r|\n/) do |match| line_feed_changed = true if match != line_feed_code line_feed_code end if line_feed_changed puts " → #{line_feed}" return true end end return false end # 行末の空白を削除する。 # Param: String str 処理対象の文字列 # Return: bool 変更の有無 def remove_trailing_spaces(str) if /[  ](?=[\r\n]|\z)/ =~ str str.gsub!(/[  ]+(?=[\r\n]|\z)/, '') puts " Trailing spaces removed." return true end return false end # ファイルへの入出力と変換の制御を行う。 # Param: String file 処理対象のファイルのパス def encode(file, input_encoding: nil, output_encoding: nil, line_feed: nil, remove_trailing_spaces: false) puts file return if File.size(file).zero? changed = false begin open(file, "r+b") do |io| # 読み込み & 文字コード判定 if input_encoding == 'AUTO' contents = io.read(512) if contents.binary? puts " binary" return end contents << io.read unless io.eof? input_encoding = NKF.guess(contents) else contents = io.read end # 内部処理の為、とりあえず UTF-8 に変換する。 contents.encode!(Encoding::UTF_8, input_encoding) # 改行コード changed |= convert_line_feed(contents, line_feed) # 行末の空白 changed |= remove_trailing_spaces(contents) if remove_trailing_spaces # 出力用文字コードに変換 changed |= convert_encoding(contents, output_encoding, input_encoding) if changed io.rewind io.truncate 0 io.write contents end end rescue puts " Error: #{$!}" puts " " + $@.first end end if $0 == __FILE__ if 0 == ARGV.size $stderr.puts "変換対象のファイルを指定して実行してください。" $stderr.puts opt exit end ARGV.each do |file| encode(file, params) end end