スポンサーリンク

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