バッチで文字列を置換する (JScriptでテキストファイル処理)
テキストファイル中の文字列を置換する場合,
普通はエディタの置換機能を使うだろう。
しかし,それが何度も行なうルーティンになっている場合,手作業をしてはいけない。
ミスが混入しないように,毎回の置換作業をバッチに任せるべきだ。
残念ながら,Windows コマンドプロンプト(.bat)ではファイル中の文字列の置換はできない。
かわりにここでは,WSHで動くJavascriptのクローンであるJScriptを使って,プレーンテキストの処理をするバッチを作成する。
作成と言っても,下記のコードをコピペするだけ。
完成したバッチファイルをダブルクリックするだけで,置換済みの新テキストファイルが生成される。
例えば,「テスト用」の設定ファイルと,「本番用」の設定ファイルがあるとしよう。
テスト用のファイル中で「localhost」となっているのを,本番用では「192.168.0.1」のように本番サーバのIPアドレスに置き換えて記述したいとする。
設定内容に変更があるたびに毎回,
- まずテスト用の設定ファイルを開き
- エディタで「localhost」を「192.168.0.1」に置換し
- 本番用のファイル名で保存し直す
という手順を踏むのは,煩雑だ。
この置換作業を一発で行なうためには,まず下記のようなバッチファイルを作成する。
ファイル名は,例えば「replace.js」のように拡張子を .js にする。
/* 旧ファイルの文字列を置換して新ファイルに書き込む 使い方 ・最初の4つの変数の値を書き換える ・ダブルクリックで実行 */ // 書き変えたい内容 var str_from = "localhost"; var str_to = "192.168.0.1"; var file_from = "data_local.conf"; var file_to = "data.conf"; // 定数 var ForReading = 1; // 読み込み var ForWriting = 2; // 書き込み(上書き) var ForAppending = 8; // 書き込み(追記) // ファイル存在チェック var fso_r = WScript.CreateObject( "Scripting.FileSystemObject" ); if( ! fso_r.FileExists( file_from ) ) { WScript.Echo( "ファイルが存在しません。" ); // 強制終了 WScript.Quit(); } // 新規ファイル作成 var fso_w = WScript.CreateObject( "Scripting.FileSystemObject" ); if( fso_w.FileExists( file_to ) ) { fso_w.DeleteFile( file_to ); } var txt_w = fso_w.CreateTextFile( file_to ); // 旧ファイルを読み込み var txt_r = fso_r.OpenTextFile( file_from, ForReading ); while( ! txt_r.AtEndOfStream ) { // 置換 str = txt_r.ReadLine(); str = str.replace( new RegExp( str_from, "g" ), str_to ); txt_w.WriteLine( str ); } txt_r.Close(); txt_w.Close(); WScript.Echo( "置換終了" );
そして,ただこの replace.js をダブルクリックすればよい。
すると data_local.conf という元ファイルの内容を置換して,新ファイル data.conf が生成される。(同じフォルダ上に置いておくこと。)
解説
JavaScriptではファイル処理は不可能だが,WSHならば専用のオブジェクトを使ってそれが可能になる。
WSHには標準でVBScriptとJScriptがある。
VBScriptでファイル処理をするための情報は巷に多くあるが,JScriptに関してはそれほど多くない。
しかし,もしJScriptで FileSystemObject の使い方を身に着ければ,JavaScriptで培ったノウハウを生かしてバッチ作成ができる。
JScriptには,一部JavaScriptと異なるコーディング作法がある。
- alert() のかわりに,WScript.Echo() を使う。
- ファイル処理専用のオブジェクトがある。
- スクリプトは WScript.Quit() で終了できる。
JavaScriptは実行のためにHTML中に埋め込む必要があるが,JScriptならばファイル単体でそのまま実行して,結果を直接出力できる。
コンパイル不要だし,ブラウザもサーバも不要。
メモ帳さえあれば,ファイル処理を行なうアプリケーションが作成できる。
最も手軽なプログラミング手段の一つと言えるだろう。(OSはWindows限定になるが)
なお,UTF-8でファイル入出力したい場合は下記を参照。
jscriptで utf8なファイル出力
http://passing.breeze.cc/mt/archives/2008/05/jscript-utf8.html
おまけ
これは昔書いた,ニュートン法のスクリプト。
//初期値、許容誤差、反復回数 var x0 = 10.0; var eps = 0.0001; var imax = 1000; function f( x ){ // y = f(x) y = x * x; return y; } function df( x ){ // y' = f'(x) dy = 2 * x; return dy; } //反復 oldx = x0; for( i = 0; i < imax; i++ ){ nextx = oldx - ( f( oldx ) / df( oldx ) ); if( Math.abs( f(nextx) ) < eps )break; else oldx = nextx; } WScript.Echo( "x = " + nextx + ", f(x) = " + f(nextx) );
導関数が既知のとき,適当な初期値を与えて f(x) = 0 なる方程式の解を数値的に求める事ができる。
やはりダブルクリックだけで実行できる。
補足
HTA形式で実行する際には,WScriptが最初から使えないので
var fso_w = WScript.CreateObject( "Scripting.FileSystemObject" );
のかわりに
var fso_w = new ActiveXObject( "Scripting.FileSystemObject" );
とする。
また、一行ずつ読むのではなくてファイル全体を丸ごと読み込む ReadAll() メソッドも便利だが、利用時は必ず
if( ! txt_r.AtEndOfStream ) { str = txt_r.ReadAll(); }
のように、ファイルの終端に達していないかどうか判定を行なうこと。
一行ずつ読み進んでいくわけでもないのに終端判定する理由は、ファイルが空の場合があるから。
ファイルが空なのに ReadAll() すると
エラー:ファイルの最後を超えた入力を行なおうとしました。
のエラーが出る。