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 * 079 * @version 4.0 080 * @author Kazuhiko Hasegawa 081 * @since JDK5.0, 082 */ 083 public class Process_GrepChange extends AbstractProcess implements ChainProcess { 084 private String[] keyword = null; 085 private String[] change = null; 086 private boolean ignoreCase = false; 087 private boolean isChange = true; // 5.1.2.0 (2010/01/01) 置換するかど?を指定可能にする 088 private String inEncode = null; 089 private String outEncode = null; 090 private boolean display = false; // 表示しな? 091 092 private int inCount = 0; 093 private int findCount = 0; 094 private int cngCount = 0; 095 096 private static final Map<String,String> mustProparty ; // ?プロパティ???チェ?用 Map 097 private static final Map<String,String> usableProparty ; // ?プロパティ?整合?チェ? Map 098 099 static { 100 mustProparty = new LinkedHashMap<String,String>(); 101 mustProparty.put( "keywordFile", "置換する語句を含?ーと値のペアー(タブ区?)(??)" ); 102 103 usableProparty = new LinkedHashMap<String,String>(); 104 usableProparty.put( "ignoreCase", "検索時に大?小文字を区別しな?true)かど?? + 105 CR + "(初期値:区別する[false])" ); 106 usableProparty.put( "isChange", "置換??実施する(true)かど?" + 107 CR + "(初期値:置換する[true])" ); 108 usableProparty.put( "inEncode", "入力ファイルのエンコードタイ? ); 109 usableProparty.put( "outEncode", "出力ファイル?ーワードファイルのエンコードタイ? ); 110 usableProparty.put( "display", "結果を標準?力に表示する(true)かしな?false)? + 111 CR + "(初期値:false:表示しな?" ); 112 } 113 114 /** 115 * ?ォルトコンストラクター? 116 * こ?クラスは、動??されます??ォルトコンストラクターで? 117 * super クラスに対して、?な初期化を行っておきます? 118 * 119 */ 120 public Process_GrepChange() { 121 super( "org.opengion.fukurou.process.Process_GrepChange",mustProparty,usableProparty ); 122 } 123 124 /** 125 * プロセスの初期化を行います?初めに??、呼び出されます? 126 * 初期処?ファイルオープン??オープン?に使用します? 127 * 128 * @og.rev 5.1.2.0 (2010/01/01) 置換するかど?を指定可能にする(isChange)属?追? 129 * 130 * @param paramProcess ??タベ?スの接続???などを持って?オブジェク? 131 */ 132 public void init( final ParamProcess paramProcess ) { 133 Argument arg = getArgument(); 134 135 String keywordFile = arg.getProparty("keywordFile" ); 136 ignoreCase = arg.getProparty("ignoreCase",ignoreCase); 137 isChange = arg.getProparty("isChange",isChange); // 5.1.2.0 (2010/01/01) 138 inEncode = arg.getProparty("inEncode",System.getProperty("file.encoding")); 139 outEncode = arg.getProparty("outEncode",System.getProperty("file.encoding")); 140 display = arg.getProparty("display",display); 141 142 FileString fs = new FileString(); 143 fs.setFilename( keywordFile ); 144 fs.setEncode( outEncode ); 145 String[] lines = fs.getValue( "\n" ); 146 int len = lines.length; 147 if( len == 0 ) { 148 String errMsg = "keywordFile の??読み取れませんでした?" + keywordFile + "]" ; 149 throw new RuntimeException( errMsg ); 150 } 151 152 println( "keywordFile を?" + len + "件読み取りました? ); 153 List<String> keyList = new ArrayList<String>( len ); 154 List<String> cngList = new ArrayList<String>( len ); 155 156 for( int i=0; i<len; i++ ) { 157 // String line = lines[i].trim(); 158 String line = lines[i]; 159 int indx = line.indexOf( '\t' ); 160 if( indx <= 0 ) { continue ; } // TAB が?頭??存在しな??読み飛?す? 161 keyList.add( line.substring( 0,indx ).trim() ); 162 String cng = line.substring( indx+1 ).trim(); 163 cng = StringUtil.replace( cng,"\\n",CR ); 164 cng = StringUtil.replace( cng,"\\t","\t" ); 165 cngList.add( cng ); 166 } 167 keyword = keyList.toArray( new String[keyList.size()] ); 168 change = cngList.toArray( new String[cngList.size()] ); 169 } 170 171 /** 172 * プロセスの終?行います??に??、呼び出されます? 173 * 終???ファイルクローズ??クローズ?に使用します? 174 * 175 * @param isOK ト?タルで、OK?たかど?[true:成功/false:失敗] 176 */ 177 public void end( final boolean isOK ) { 178 // ここでは処?行いません? 179 } 180 181 /** 182 * 引数の LineModel を??るメソ?です? 183 * 変換処?? LineModel を返します? 184 * 後続??行わな?????タのフィルタリングを行う場?は? 185 * null ??タを返します?つまり?null ??タは、後続??行わな? 186 * フラグの代わりにも使用して?す? 187 * なお?変換処?? LineModel と、オリジナルの LineModel が? 188 * 同?、コピ?(クローン)か?、各処?ソ??決めて?す? 189 * ドキュメントに明記されて???合?、副作用が問題になる?合?? 190 * ???とに自?コピ?(クローン)して下さ?? 191 * 192 * @og.rev 4.0.0.0 (2007/11/28) メソ?の戻り?をチェ?します? 193 * @og.rev 5.1.2.0 (2010/01/01) 置換するかど?を指定可能にする(isChange)属?追? 194 * 195 * @param data オリジナルのLineModel 196 * 197 * @return 処?換後?LineModel 198 */ 199 public LineModel action( final LineModel data ) { 200 inCount++ ; 201 final FileLineModel fileData ; 202 if( data instanceof FileLineModel ) { 203 fileData = (FileLineModel)data ; 204 } 205 else { 206 String errMsg = "??タ?FileLineModel オブジェクトではありません? + CR ; 207 throw new RuntimeException( errMsg ); 208 } 209 210 File org = fileData.getFile() ; 211 String orgName = org.getPath(); 212 if( ! org.isFile() ) { return data; } 213 214 BufferedReader reader = FileUtil.getBufferedReader( org,inEncode ); 215 // File tempFile = new File( org.getPath() + "_temp" ); 216 // PrintWriter tempWrt = FileUtil.getPrintWriter( tempFile,outEncode ); 217 File tempFile = null; 218 PrintWriter tempWrt = null; 219 220 // 5.1.2.0 (2010/01/01) 置換する?合?前?? 221 if( isChange ) { 222 tempFile = new File( orgName + "_temp" ); 223 tempWrt = FileUtil.getPrintWriter( tempFile,outEncode ); 224 } 225 226 boolean nextFlag = false; 227 228 try { 229 String line ; 230 int lineNo = 0; 231 while((line = reader.readLine()) != null) { 232 lineNo++ ; 233 StringBuilder buf = new StringBuilder( line ); 234 // boolean foundFlag = false; // 行単位に初期化する? 235 for( int i=0; i<keyword.length; i++ ) { 236 int indx = buf.indexOf( keyword[i] ); 237 // 置換対象発見?行?力用に見つかれば、true にする? 238 if( indx >= 0 ) { 239 // foundFlag = true; 240 nextFlag = true; // ?度でも見つかれば、true にセ? 241 if( display ) { println( orgName + ":" + lineNo + ":" + keyword[i] + ":" + line ); } 242 } 243 // 置換対象が見つかっても?isChange=true でなければ、置換???行わな?? 244 if( isChange ) { 245 while( indx >= 0 ) { 246 buf.replace( indx,indx+keyword[i].length(),change[i] ); 247 indx = buf.indexOf( keyword[i],indx+change[i].length() ); 248 // nextFlag = true; // キーワードが存在したファイル? 249 cngCount++ ; 250 findCount++ ; 251 } 252 } 253 } 254 // 5.1.2.0 (2010/01/01) 置換する?合?処? 255 if( isChange ) { 256 tempWrt.println( buf.toString() ); 257 } 258 } 259 } 260 catch ( IOException ex ) { 261 String errMsg = "処?にエラーが発生しました?" + data.getRowNo() + "]件目" + CR 262 + data.toString() ; 263 throw new RuntimeException( errMsg,ex ); 264 } 265 finally { 266 Closer.ioClose( reader ); 267 Closer.ioClose( tempWrt ); 268 } 269 270 // 5.1.2.0 (2010/01/01) 置換する?合?処? 271 if( isChange ) { 272 if( nextFlag ) { 273 if( !org.delete() ) { 274 String errMsg = "??ファイルを削除できませんでした?" + org + "]" ; 275 throw new RuntimeException( errMsg ); 276 } 277 if( !tempFile.renameTo( org ) ) { 278 String errMsg = "??ファイルをリネ??きませんでした?" + tempFile + "]" ; 279 throw new RuntimeException( errMsg ); 280 } 281 } 282 else { 283 if( !tempFile.delete() ) { 284 String errMsg = "??ファイルを削除できませんでした?" + tempFile + "]" ; 285 throw new RuntimeException( errMsg ); 286 } 287 } 288 } 289 290 return (nextFlag) ? data : null ; 291 } 292 293 /** 294 * プロセスの処?果のレポ?ト表現を返します? 295 * 処??ログラ?、?力件数、?力件数などの??です? 296 * こ???をそのまま、標準?力に出すことで、結果レポ?トと出来るよ? 297 * 形式で出してください? 298 * 299 * @return 処?果のレポ?? 300 */ 301 public String report() { 302 String report = "[" + getClass().getName() + "]" + CR 303 + TAB + "Search File Count : " + inCount + CR 304 + TAB + "Key Find Count : " + findCount + CR 305 + TAB + "Key Change Count : " + cngCount ; 306 307 return report ; 308 } 309 310 /** 311 * こ?クラスの使用方法を返します? 312 * 313 * @return こ?クラスの使用方? 314 */ 315 public String usage() { 316 StringBuilder buf = new StringBuilder(); 317 318 buf.append( "Process_GrepChange は、上流から受け取っ?FileLineModelから、語句? ).append( CR ); 319 buf.append( "置換する?ChainProcess インターフェースの実?ラスです?" ).append( CR ); 320 buf.append( "Process_Grep との違いは、チェ?するファイルのコピ??キーワードが存在" ).append( CR ); 321 buf.append( "しなくと?作?することと、検索キーに正規表現が使えな???行置き換えが" ).append( CR ); 322 buf.append( "出来な?とです?" ).append( CR ); 323 buf.append( CR ); 324 buf.append( "keywordFile より、置換する語句を含?ーと値のペアー(タブ区?)を読取り? ).append( CR ); 325 buf.append( "対象とする語句を置換します?" ).append( CR ); 326 buf.append( "keywordFile に、タブが含まれな?や、?頭にタブが存在して?場合?? ).append( CR ); 327 buf.append( "そ?行を読み飛?します?また?区?タブ?何?存在しても構いません? ).append( CR ); 328 buf.append( "ただし?タブで区?た前(キー)と後ろ(値)は、trim() されます?で、スペ?ス" ).append( CR ); 329 buf.append( "が前後に存在して?場合?、ご注意く???" ).append( CR ); 330 buf.append( "置換文?値)は、\t と \n の特殊文字が使用できます?" ).append( CR ); 331 buf.append( "こ? GrepChange では、語句に、正規表現は使用できません。正規表現のキーワー? ).append( CR ); 332 buf.append( "?字?を?行???と置き換える場合?、Process_Grep を使用して下さ??" ).append( CR ); 333 buf.append( "こ?プログラ?は、上流から受け取っ?FileLineModel のファイルに対して? ).append( CR ); 334 buf.append( "置き換えた結果も?同じファイルにセーブします?" ).append( CR ); 335 buf.append( "??ファイルを保存したい場合?、予めバックア??を取得しておいてください? ).append( CR ); 336 buf.append( "-inEncode は、?力ファイルのエンコード指定になります?" ).append( CR ); 337 buf.append( "-outEncode は、?力ファイルのエンコードや、キーワードファイルのエンコー? ).append( CR ); 338 buf.append( "?になります?(keywordFile は、? 出力ファイルと同じエンコードです?)" ).append( CR ); 339 buf.append( "これら?エンコードが無??場合?、System.getProperty(\"file.encoding\") " ).append( CR ); 340 buf.append( "で求まる?を使用します?" ).append( CR ); 341 buf.append( CR ); 342 buf.append( "上流?ロセスでは、Name 属?として、?File』を持ち、?は、Fileオブジェク? ).append( CR ); 343 buf.append( "である、Process_FileSearch を使用するのが?便利です?それ以外?クラス? ).append( CR ); 344 buf.append( "使用する場合でも?Name属?と、File オブジェクトを持つ LineModel を受け渡? ).append( CR ); 345 buf.append( "できれば、使用可能です?" ).append( CR ); 346 buf.append( CR ); 347 buf.append( "引数??中に空白を含??合?、ダブルコー??ション(\"\") で括って下さ??" ).append( CR ); 348 buf.append( "引数??の ?』?前後には、空白は挟めません。??key=value の様に" ).append( CR ); 349 buf.append( "繋げてください? ).append( CR ); 350 buf.append( CR ).append( CR ); 351 352 buf.append( getArgument().usage() ).append( CR ); 353 354 return buf.toString(); 355 } 356 357 /** 358 * こ?クラスは、main メソ?から実行できません? 359 * 360 * @param args コマンド引数配? 361 */ 362 public static void main( final String[] args ) { 363 LogWriter.log( new Process_GrepChange().usage() ); 364 } 365 }