001 /* 002 * Copyright (c) 2009 The openGion Project. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 013 * either express or implied. See the License for the specific language 014 * governing permissions and limitations under the License. 015 */ 016 package org.opengion.fukurou.process; 017 018 import org.opengion.fukurou.util.Argument; 019 import org.opengion.fukurou.util.FileUtil; 020 import org.opengion.fukurou.util.FileString; 021 import org.opengion.fukurou.util.Closer ; 022 import org.opengion.fukurou.util.StringUtil ; 023 import org.opengion.fukurou.util.LogWriter; 024 025 import java.util.Map ; 026 import java.util.LinkedHashMap ; 027 import java.util.List ; 028 import java.util.ArrayList ; 029 030 import java.io.File; 031 import java.io.PrintWriter; 032 import java.io.BufferedReader; 033 import java.io.IOException; 034 035 /** 036 * Process_GrepChange は、上流から受け取っ?FileLineModelから、語句? 037 * 置換する?ChainProcess インターフェースの実?ラスです? 038 * 039 * Process_Grep との違いは、チェ?するファイルのコピ??キーワードが存在 040 * しなくと?作?することと、検索キーに正規表現が使えな???行置き換えが 041 * 出来な?とです? 042 * 043 * keywordFile より、置換する語句を含?ーと値のペアー(タブ区?)を読取り? 044 * 対象とする語句を置換します? 045 * keywordFile に、タブが含まれな?や、?頭にタブが存在して?場合?? 046 * そ?行を読み飛?します?また?区?タブ?何?存在しても構いません? 047 * ただし?タブで区?た前(キー)と後ろ(値)は、trim() されます?で、スペ?ス 048 * が前後に存在して?場合?、ご注意く??? 049 * 置換文?値)は、\t と \n の特殊文字が使用できます? 050 * こ? GrepChange では、語句に、正規表現は使用できません。正規表現のキーワー? 051 * ?字?を?行???と置き換える場合?、Process_Grep を使用してください? 052 * こ?プログラ?は、上流から受け取っ?FileLineModel のファイルに対して? 053 * 置き換えた結果も?同じファイルにセーブします? 054 * ??ファイルを保存したい場合?、予めバックア??を取得しておいてください? 055 * -inEncode は、?力ファイルのエンコード指定になります? 056 * -outEncode は、?力ファイルのエンコードや、キーワードファイルの 057 * エンコード指定になります?(keywordFile は、? 出力ファイルと同じエンコードです?) 058 * これら?エンコードが無??場合?、System.getProperty("file.encoding") で 059 * 求まる?を使用します? 060 * 061 * 上流?ロセスでは、Name 属?として、?File』を持ち、?は、Fileオブジェク? 062 * である、Process_FileSearch を使用するのが?便利です?それ以外?クラス? 063 * 使用する場合でも?Name属?と、File オブジェクトを持つ LineModel を受け渡? 064 * できれば、使用可能です? 065 * 066 * 引数??中にスペ?スを含??合?、ダブルコー??ション("") で括って下さ?? 067 * 引数??の ?』?前後には、スペ?スは挟めません。??key=value の様に 068 * 繋げてください? 069 * 070 * Process_GrepChange -keyword=検索?? -ignoreCase=true -outfile=OUTFILE -encode=UTF-8 071 * 072 * -keywordFile=キーワー? ?置換する語句を含?ーと値のペアー(タブ区?) 073 * [-ignoreCase=大?小文?] ?検索時に大?小文字を区別しな?true)かど?(初期値:false[区別する]) 074 * [-isChange=置換可否 ] ?置換??実施する(true)かど?(初期値:置換する[true]) 075 * [-inEncode=入力エンコー?] ??力ファイルのエンコードタイ? 076 * [-outEncode=出力エンコード] ??力ファイル?ーワードファイルのエンコードタイ? 077 * [-display=false|true ] ?結果を標準?力に表示する(true)かしな?false)?初期値:false[表示しない]) 078 * [-debug=false|true ] ?デバッグ??を標準?力に表示する(true)かしな?false)?初期値:false[表示しない]) 079 * 080 * @version 4.0 081 * @author Kazuhiko Hasegawa 082 * @since JDK5.0, 083 */ 084 public class Process_GrepChange extends AbstractProcess implements ChainProcess { 085 private String[] keyword = null; 086 private String[] change = null; 087 private boolean ignoreCase = false; 088 private boolean isChange = true; // 5.1.2.0 (2010/01/01) 置換するかど?を指定可能にする 089 private String inEncode = null; 090 private String outEncode = null; 091 private boolean display = false; // 表示しな? 092 private boolean debug = false; // 5.7.3.0 (2014/02/07) ???? 093 094 private int inCount = 0; 095 private int findCount = 0; 096 private int cngCount = 0; 097 098 private static final Map<String,String> mustProparty ; // ?プロパティ???チェ?用 Map 099 private static final Map<String,String> usableProparty ; // ?プロパティ?整合?チェ? Map 100 101 static { 102 mustProparty = new LinkedHashMap<String,String>(); 103 mustProparty.put( "keywordFile", "置換する語句を含?ーと値のペアー(タブ区?)(??)" ); 104 105 usableProparty = new LinkedHashMap<String,String>(); 106 usableProparty.put( "ignoreCase", "検索時に大?小文字を区別しな?true)かど?? + 107 CR + "(初期値:区別する[false])" ); 108 usableProparty.put( "isChange", "置換??実施する(true)かど?" + 109 CR + "(初期値:置換する[true])" ); 110 usableProparty.put( "inEncode", "入力ファイルのエンコードタイ? ); 111 usableProparty.put( "outEncode", "出力ファイル?ーワードファイルのエンコードタイ? ); 112 usableProparty.put( "display", "結果を標準?力に表示する(true)かしな?false)? + 113 CR + "(初期値:false:表示しな?" ); 114 usableProparty.put( "debug", "????を標準?力に表示する(true)かしな?false)? + 115 CR + "(初期値:false:表示しな?" ); // 5.7.3.0 (2014/02/07) ???? 116 } 117 118 /** 119 * ?ォルトコンストラクター? 120 * こ?クラスは、動??されます??ォルトコンストラクターで? 121 * super クラスに対して、?な初期化を行っておきます? 122 * 123 */ 124 public Process_GrepChange() { 125 super( "org.opengion.fukurou.process.Process_GrepChange",mustProparty,usableProparty ); 126 } 127 128 /** 129 * プロセスの初期化を行います?初めに??、呼び出されます? 130 * 初期処?ファイルオープン??オープン?に使用します? 131 * 132 * @og.rev 5.1.2.0 (2010/01/01) 置換するかど?を指定可能にする(isChange)属?追? 133 * 134 * @param paramProcess ??タベ?スの接続???などを持って?オブジェク? 135 */ 136 public void init( final ParamProcess paramProcess ) { 137 Argument arg = getArgument(); 138 139 String keywordFile = arg.getProparty("keywordFile" ); 140 ignoreCase = arg.getProparty("ignoreCase",ignoreCase); 141 isChange = arg.getProparty("isChange",isChange); // 5.1.2.0 (2010/01/01) 142 inEncode = arg.getProparty("inEncode",System.getProperty("file.encoding")); 143 outEncode = arg.getProparty("outEncode",System.getProperty("file.encoding")); 144 display = arg.getProparty("display",display); 145 debug = arg.getProparty("debug",debug); // 5.7.3.0 (2014/02/07) ???? 146 // if( debug ) { println( arg.toString() ); } // 5.7.3.0 (2014/02/07) ???? 147 148 FileString fs = new FileString(); 149 fs.setFilename( keywordFile ); 150 fs.setEncode( outEncode ); 151 String[] lines = fs.getValue( "\n" ); 152 int len = lines.length; 153 if( len == 0 ) { 154 String errMsg = "keywordFile の??読み取れませんでした?" + keywordFile + "]" ; 155 throw new RuntimeException( errMsg ); 156 } 157 158 println( "keywordFile を?" + len + "件読み取りました? ); 159 List<String> keyList = new ArrayList<String>( len ); 160 List<String> cngList = new ArrayList<String>( len ); 161 162 for( int i=0; i<len; i++ ) { 163 // String line = lines[i].trim(); 164 String line = lines[i]; 165 int indx = line.indexOf( '\t' ); 166 if( indx <= 0 ) { continue ; } // TAB が?頭??存在しな??読み飛?す? 167 keyList.add( line.substring( 0,indx ).trim() ); 168 String cng = line.substring( indx+1 ).trim(); 169 cng = StringUtil.replace( cng,"\\n",CR ); 170 cng = StringUtil.replace( cng,"\\t","\t" ); 171 cngList.add( cng ); 172 } 173 keyword = keyList.toArray( new String[keyList.size()] ); 174 change = cngList.toArray( new String[cngList.size()] ); 175 } 176 177 /** 178 * プロセスの終?行います??に??、呼び出されます? 179 * 終???ファイルクローズ??クローズ?に使用します? 180 * 181 * @param isOK ト?タルで、OK?たかど?[true:成功/false:失敗] 182 */ 183 public void end( final boolean isOK ) { 184 // ここでは処?行いません? 185 } 186 187 /** 188 * 引数の LineModel を??るメソ?です? 189 * 変換処?? LineModel を返します? 190 * 後続??行わな?????タのフィルタリングを行う場?は? 191 * null ??タを返します?つまり?null ??タは、後続??行わな? 192 * フラグの代わりにも使用して?す? 193 * なお?変換処?? LineModel と、オリジナルの LineModel が? 194 * 同?、コピ?(クローン)か?、各処?ソ??決めて?す? 195 * ドキュメントに明記されて???合?、副作用が問題になる?合?? 196 * ???とに自?コピ?(クローン)して下さ?? 197 * 198 * @og.rev 4.0.0.0 (2007/11/28) メソ?の戻り?をチェ?します? 199 * @og.rev 5.1.2.0 (2010/01/01) 置換するかど?を指定可能にする(isChange)属?追? 200 * @og.rev 5.7.2.2 (2014/01/24) エラー時に??タも?力します? 201 * 202 * @param data オリジナルのLineModel 203 * 204 * @return 処?換後?LineModel 205 */ 206 public LineModel action( final LineModel data ) { 207 inCount++ ; 208 final FileLineModel fileData ; 209 if( data instanceof FileLineModel ) { 210 fileData = (FileLineModel)data ; 211 } 212 else { 213 String errMsg = "??タ?FileLineModel オブジェクトではありません? + CR ; 214 throw new RuntimeException( errMsg ); 215 } 216 217 218 File org = fileData.getFile() ; 219 String orgName = org.getPath(); 220 if( ! org.isFile() ) { return data; } 221 222 if( debug ) { println( "File:" + org ); } // 5.1.2.0 (2010/01/01) display の条件変更 223 224 BufferedReader reader = FileUtil.getBufferedReader( org,inEncode ); 225 // File tempFile = new File( org.getPath() + "_temp" ); 226 // PrintWriter tempWrt = FileUtil.getPrintWriter( tempFile,outEncode ); 227 File tempFile = null; 228 PrintWriter tempWrt = null; 229 230 // 5.1.2.0 (2010/01/01) 置換する?合?前?? 231 if( isChange ) { 232 tempFile = new File( orgName + "_temp" ); 233 tempWrt = FileUtil.getPrintWriter( tempFile,outEncode ); 234 } 235 236 boolean nextFlag = false; 237 238 try { 239 String line ; 240 int lineNo = 0; 241 while((line = reader.readLine()) != null) { 242 lineNo++ ; 243 StringBuilder buf = new StringBuilder( line ); 244 // boolean foundFlag = false; // 行単位に初期化する? 245 for( int i=0; i<keyword.length; i++ ) { 246 int indx = buf.indexOf( keyword[i] ); 247 // 置換対象発見?行?力用に見つかれば、true にする? 248 if( indx >= 0 ) { 249 // foundFlag = true; 250 nextFlag = true; // ?度でも見つかれば、true にセ? 251 if( display ) { println( orgName + ":" + lineNo + ":" + keyword[i] + ":" + line ); } 252 } 253 // 置換対象が見つかっても?isChange=true でなければ、置換???行わな?? 254 if( isChange ) { 255 while( indx >= 0 ) { 256 buf.replace( indx,indx+keyword[i].length(),change[i] ); 257 indx = buf.indexOf( keyword[i],indx+change[i].length() ); 258 // nextFlag = true; // キーワードが存在したファイル? 259 cngCount++ ; 260 findCount++ ; 261 } 262 } 263 } 264 // 5.1.2.0 (2010/01/01) 置換する?合?処? 265 if( isChange ) { 266 tempWrt.println( buf.toString() ); 267 } 268 } 269 } 270 catch ( IOException ex ) { 271 String errMsg = "処?にエラーが発生しました?" + data.getRowNo() + "]件目" + CR 272 // + data.toString() ; 273 + "data=[" + data.dataLine() + "]" + CR ; // 5.7.2.2 (2014/01/24) エラー時に??タも?力します? 274 throw new RuntimeException( errMsg,ex ); 275 } 276 finally { 277 Closer.ioClose( reader ); 278 Closer.ioClose( tempWrt ); 279 } 280 281 // 5.1.2.0 (2010/01/01) 置換する?合?処? 282 if( isChange ) { 283 if( nextFlag ) { 284 if( !org.delete() ) { 285 String errMsg = "??ファイルを削除できませんでした?" + org + "]" + CR 286 + "data=[" + data.dataLine() + "]" + CR ; // 5.7.2.2 (2014/01/24) エラー時に??タも?力します? 287 throw new RuntimeException( errMsg ); 288 } 289 if( !tempFile.renameTo( org ) ) { 290 String errMsg = "??ファイルをリネ??きませんでした?" + tempFile + "]" + CR 291 + "data=[" + data.dataLine() + "]" + CR ; // 5.7.2.2 (2014/01/24) エラー時に??タも?力します? 292 throw new RuntimeException( errMsg ); 293 } 294 } 295 else { 296 if( !tempFile.delete() ) { 297 String errMsg = "??ファイルを削除できませんでした?" + tempFile + "]" + CR 298 + "data=[" + data.dataLine() + "]" + CR ; // 5.7.2.2 (2014/01/24) エラー時に??タも?力します? 299 throw new RuntimeException( errMsg ); 300 } 301 } 302 } 303 304 return (nextFlag) ? data : null ; 305 } 306 307 /** 308 * プロセスの処?果のレポ?ト表現を返します? 309 * 処??ログラ?、?力件数、?力件数などの??です? 310 * こ???をそのまま、標準?力に出すことで、結果レポ?トと出来るよ? 311 * 形式で出してください? 312 * 313 * @return 処?果のレポ?? 314 */ 315 public String report() { 316 String report = "[" + getClass().getName() + "]" + CR 317 + TAB + "Search File Count : " + inCount + CR 318 + TAB + "Key Find Count : " + findCount + CR 319 + TAB + "Key Change Count : " + cngCount ; 320 321 return report ; 322 } 323 324 /** 325 * こ?クラスの使用方法を返します? 326 * 327 * @return こ?クラスの使用方? 328 */ 329 public String usage() { 330 StringBuilder buf = new StringBuilder(); 331 332 buf.append( "Process_GrepChange は、上流から受け取っ?FileLineModelから、語句? ).append( CR ); 333 buf.append( "置換する?ChainProcess インターフェースの実?ラスです?" ).append( CR ); 334 buf.append( "Process_Grep との違いは、チェ?するファイルのコピ??キーワードが存在" ).append( CR ); 335 buf.append( "しなくと?作?することと、検索キーに正規表現が使えな???行置き換えが" ).append( CR ); 336 buf.append( "出来な?とです?" ).append( CR ); 337 buf.append( CR ); 338 buf.append( "keywordFile より、置換する語句を含?ーと値のペアー(タブ区?)を読取り? ).append( CR ); 339 buf.append( "対象とする語句を置換します?" ).append( CR ); 340 buf.append( "keywordFile に、タブが含まれな?や、?頭にタブが存在して?場合?? ).append( CR ); 341 buf.append( "そ?行を読み飛?します?また?区?タブ?何?存在しても構いません? ).append( CR ); 342 buf.append( "ただし?タブで区?た前(キー)と後ろ(値)は、trim() されます?で、スペ?ス" ).append( CR ); 343 buf.append( "が前後に存在して?場合?、ご注意く???" ).append( CR ); 344 buf.append( "置換文?値)は、\t と \n の特殊文字が使用できます?" ).append( CR ); 345 buf.append( "こ? GrepChange では、語句に、正規表現は使用できません。正規表現のキーワー? ).append( CR ); 346 buf.append( "?字?を?行???と置き換える場合?、Process_Grep を使用して下さ??" ).append( CR ); 347 buf.append( "こ?プログラ?は、上流から受け取っ?FileLineModel のファイルに対して? ).append( CR ); 348 buf.append( "置き換えた結果も?同じファイルにセーブします?" ).append( CR ); 349 buf.append( "??ファイルを保存したい場合?、予めバックア??を取得しておいてください? ).append( CR ); 350 buf.append( "-inEncode は、?力ファイルのエンコード指定になります?" ).append( CR ); 351 buf.append( "-outEncode は、?力ファイルのエンコードや、キーワードファイルのエンコー? ).append( CR ); 352 buf.append( "?になります?(keywordFile は、? 出力ファイルと同じエンコードです?)" ).append( CR ); 353 buf.append( "これら?エンコードが無??場合?、System.getProperty(\"file.encoding\") " ).append( CR ); 354 buf.append( "で求まる?を使用します?" ).append( CR ); 355 buf.append( CR ); 356 buf.append( "上流?ロセスでは、Name 属?として、?File』を持ち、?は、Fileオブジェク? ).append( CR ); 357 buf.append( "である、Process_FileSearch を使用するのが?便利です?それ以外?クラス? ).append( CR ); 358 buf.append( "使用する場合でも?Name属?と、File オブジェクトを持つ LineModel を受け渡? ).append( CR ); 359 buf.append( "できれば、使用可能です?" ).append( CR ); 360 buf.append( CR ); 361 buf.append( "引数??中に空白を含??合?、ダブルコー??ション(\"\") で括って下さ??" ).append( CR ); 362 buf.append( "引数??の ?』?前後には、空白は挟めません。??key=value の様に" ).append( CR ); 363 buf.append( "繋げてください? ).append( CR ); 364 buf.append( CR ).append( CR ); 365 366 buf.append( getArgument().usage() ).append( CR ); 367 368 return buf.toString(); 369 } 370 371 /** 372 * こ?クラスは、main メソ?から実行できません? 373 * 374 * @param args コマンド引数配? 375 */ 376 public static void main( final String[] args ) { 377 LogWriter.log( new Process_GrepChange().usage() ); 378 } 379 }