UTF8Nの複数テキストを,一斉に置換するバッチ (JScriptでUTF8Nのファイルを読み書き)
UTF-8 (BOM無し)のファイルがたくさんある。(例えばRuby on Railsのプロジェクトとか)
これらのファイル内の文字列を,一斉に置換したい。
そのためのスクリプト。
サンプルコード
置換したい文字列を下記のようにテキスト内に保存。
置換前と置換後をタブ区切りにする。
replace.txt
hoge fuga ほげ ふが <option value="(.*)"> <option class="aaa" value="$1"> params\[( )*([^\] ]+)( )*\] params[ $2 ]
正規表現も使える。
4番目の例は,ソースコードの書き方を自動整形している。
params[ hoge ] params[hoge] params[hoge ]
などが,すべて
- params[ hoge ]
に変換される。
そして,WSHバッチを動かすためのタスクを下記のように定義。
replace.wsf
<job> <script language="JavaScript" src="utf8n.js"></script> <script language="JavaScript"> var uh = new UTF8nHandler(); // フォルダ再帰の出発点 uh.set_root_path(".\\Rails\\app"); // 置換文字列が書いてあるファイル uh.load_replace_strings(".\\replace.txt"); // 置換対象のファイルの拡張子 uh.set_exts(["rb", "rhtml"]); // 置換実行 uh.exec_replace(); </script> </job>
set_root_pathのところで,再帰的にファイル探索を始めるスタート地点のフォルダを指定。
置換対象のファイルの拡張子は,いくつでも指定可能。
そして,後述するutf8n.jsを.wsfと同じディレクトリにおいた状態で,コマンドプロンプトから
cscript replace.wsf
とする。
全ファイル内の文字列が,全置換文字列に対して置換される。
(置換が発生した場合のみファイルが上書き保存される。)
UTF8Nで置換を行なうためのライブラリ
上記を実行するのに必要なライブラリ。
utf8n.js
/* utf-8nのファイル内をいっせいに置換するクラス */ var UTF8nHandler = function(){}; UTF8nHandler.prototype = { /* public */ set_root_path : function( root_path ) { this._root_path = root_path; } , // 置換文字列をセット(タブ区切りのSJISのtxtから読み込み) load_replace_strings : function( txt_path ) { var ForReading = 1; // 読み込み var ForWriting = 2; // 書き込み(上書き) var ForAppending = 8; // 書き込み(追記) var fso_r = WScript.CreateObject( "Scripting.FileSystemObject" ); var txt_r = fso_r.OpenTextFile( txt_path, ForReading ); var str; while( ! txt_r.AtEndOfStream ) { str = txt_r.ReadLine(); // タブ区切りであれば登録 if( str.match( new RegExp("^(.*)\\t(.*)$") ) ) { this._replace_strings.push([ RegExp.$1, RegExp.$2 ]); } } txt_r.Close(); } , // 拡張子をセット set_exts : function( exts ) { this._exts = exts; } , // 置換実行 exec_replace : function() { var arr_files = this._get_filtered_files(); // 全ファイルに対して var file_path; for( var i = 0; i < arr_files.length; i ++ ) { file_path = arr_files[i]; // このファイル内で置換 this._replace_one_file( file_path ); } this._log( "全" + arr_files.length + "ファイルを処理しました。" ); } , /* private */ // ------------------- 置換に関係するメンバ ------------------- // 置換を開始するディレクトリ _root_path : null, // 置換対象の文字列 _replace_strings : [], // 置換対象の拡張子 _exts : [], // root_path以下の全ファイルパスを取得 _get_all_files : function() { var ws = WScript.CreateObject("WScript.Shell"); ws.CurrentDirectory = this._root_path; var proc = ws.Exec("cmd.exe /c dir /s /b *"); var res = proc.StdOut.ReadAll().split("\r\n"); res.pop(); // 最後の行は空白 return res; } , // root_path以下で,拡張子の条件にかなう全ファイルパスを取得 _get_filtered_files : function() { // 全ファイル var all_files = this._get_all_files(); // 拡張子でふるいにかける var filtered_files = []; var file_path; for( var i = 0; i < all_files.length; i ++ ) { file_path = all_files[i]; if( this._is_target_ext( file_path ) ) { filtered_files.push( file_path ); } } return filtered_files; } , // ファイルが対象とする拡張子かどうか判定します _is_target_ext : function( file_path ) { var ext; for( var i = 0; i < this._exts.length; i ++ ) { ext = this._exts[i]; if( file_path.match( new RegExp( "\\." + ext + "$" ) ) ) { return true; } } return false; } , // 1ファイル内で置換実行 _replace_one_file : function( file_path ) { this._log( file_path + " を置換します・・・" ); // 全読み込み var str = this._load_txt( file_path ); var orig_str = str; // 各文字列に対して置換実行 var before, after; for( var i = 0; i < this._replace_strings.length; i ++ ) { before = this._replace_strings[i][0]; after = this._replace_strings[i][1]; str = str.replace( new RegExp( before, "g" ), after ); } // 置換があれば保存 if( orig_str != str ) { this._save_txt( file_path, str ); } } , // ------------------- UTF8nでの読み書きに関係するメンバ ------------------- adTypeBinary : 1, // バイナリ adTypeText : 2, // テキスト adReadAll : -1, // 全行 adReadLine : -2, // 一行ごと adWriteChar : 0, // 改行なし adWriteLine : 1, // 改行あり adSaveCreateNotExist : 1, // ない場合は新規作成 adSaveCreateOverWrite : 2, // ある場合は上書き // 全行読み込み _load_txt : function( file_path ) { // WSHでUTF8で読み書き // http://language-and-engineering.hatenablog.jp/entry/20090203/p1 // 読み込みはBOMの有無関係なし var sr = new ActiveXObject("ADODB.Stream"); sr.Type = this.adTypeText; sr.charset = "utf-8"; sr.Open(); sr.LoadFromFile( file_path ); var str = sr.ReadText( this.adReadAll ); sr.Close(); return str; } , // UTF8Nで全行書き込み _save_txt : function( file_path, str ) { // VBAでUTF8Nで読み書き // http://language-and-engineering.hatenablog.jp/entry/20090704/p1 var sw = new ActiveXObject("ADODB.Stream"); sw.Type = this.adTypeText; sw.charset = "utf-8"; sw.Open(); sw.WriteText( str, this.adWriteChar ); // 先頭のBOM取り sw.Position = 0; sw.Type = this.adTypeBinary; sw.Position = 3; var byte_data = sw.Read(); sw.Close(); // UTF-8Nコードのデータを保存 sw.Open(); sw.Type = this.adTypeBinary; sw.Write( byte_data ); sw.SaveToFile( file_path, this.adSaveCreateOverWrite ); sw.Close(); } , // ------------------- その他のメンバ ------------------- // ログ _log : function( str ) { WScript.Echo( str ); } };
補足
SJISでの置換バッチはこちら。
バッチで文字列を置換する (JScriptでテキストファイル処理)
http://language-and-engineering.hatenablog.jp/entry/20081017/1224168811
UTF8(BOM有)での置換バッチはこちら。
JScript・WSHで、UTF-8でファイルの読み書きをする方法 (ADODB.Streamで文字コード変換するサンプルコード)
http://language-and-engineering.hatenablog.jp/entry/20090203/p1