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 * @og.rev 5.7.2.2 (2014/01/24) エラー時に??タも?力します? 195 * 196 * @param data オリジナルのLineModel 197 * 198 * @return 処?換後?LineModel 199 */ 200 public LineModel action( final LineModel data ) { 201 inCount++ ; 202 final FileLineModel fileData ; 203 if( data instanceof FileLineModel ) { 204 fileData = (FileLineModel)data ; 205 } 206 else { 207 String errMsg = "??タ?FileLineModel オブジェクトではありません? + CR ; 208 throw new RuntimeException( errMsg ); 209 } 210 211 File org = fileData.getFile() ; 212 String orgName = org.getPath(); 213 if( ! org.isFile() ) { return data; } 214 215 BufferedReader reader = FileUtil.getBufferedReader( org,inEncode ); 216 // File tempFile = new File( org.getPath() + "_temp" ); 217 // PrintWriter tempWrt = FileUtil.getPrintWriter( tempFile,outEncode ); 218 File tempFile = null; 219 PrintWriter tempWrt = null; 220 221 // 5.1.2.0 (2010/01/01) 置換する?合?前?? 222 if( isChange ) { 223 tempFile = new File( orgName + "_temp" ); 224 tempWrt = FileUtil.getPrintWriter( tempFile,outEncode ); 225 } 226 227 boolean nextFlag = false; 228 229 try { 230 String line ; 231 int lineNo = 0; 232 while((line = reader.readLine()) != null) { 233 lineNo++ ; 234 StringBuilder buf = new StringBuilder( line ); 235 // boolean foundFlag = false; // 行単位に初期化する? 236 for( int i=0; i<keyword.length; i++ ) { 237 int indx = buf.indexOf( keyword[i] ); 238 // 置換対象発見?行?力用に見つかれば、true にする? 239 if( indx >= 0 ) { 240 // foundFlag = true; 241 nextFlag = true; // ?度でも見つかれば、true にセ? 242 if( display ) { println( orgName + ":" + lineNo + ":" + keyword[i] + ":" + line ); } 243 } 244 // 置換対象が見つかっても?isChange=true でなければ、置換???行わな?? 245 if( isChange ) { 246 while( indx >= 0 ) { 247 buf.replace( indx,indx+keyword[i].length(),change[i] ); 248 indx = buf.indexOf( keyword[i],indx+change[i].length() ); 249 // nextFlag = true; // キーワードが存在したファイル? 250 cngCount++ ; 251 findCount++ ; 252 } 253 } 254 } 255 // 5.1.2.0 (2010/01/01) 置換する?合?処? 256 if( isChange ) { 257 tempWrt.println( buf.toString() ); 258 } 259 } 260 } 261 catch ( IOException ex ) { 262 String errMsg = "処?にエラーが発生しました?" + data.getRowNo() + "]件目" + CR 263 // + data.toString() ; 264 + "data=[" + data.dataLine() + "]" + CR ; // 5.7.2.2 (2014/01/24) エラー時に??タも?力します? 265 throw new RuntimeException( errMsg,ex ); 266 } 267 finally { 268 Closer.ioClose( reader ); 269 Closer.ioClose( tempWrt ); 270 } 271 272 // 5.1.2.0 (2010/01/01) 置換する?合?処? 273 if( isChange ) { 274 if( nextFlag ) { 275 if( !org.delete() ) { 276 String errMsg = "??ファイルを削除できませんでした?" + org + "]" + CR 277 + "data=[" + data.dataLine() + "]" + CR ; // 5.7.2.2 (2014/01/24) エラー時に??タも?力します? 278 throw new RuntimeException( errMsg ); 279 } 280 if( !tempFile.renameTo( org ) ) { 281 String errMsg = "??ファイルをリネ??きませんでした?" + tempFile + "]" + CR 282 + "data=[" + data.dataLine() + "]" + CR ; // 5.7.2.2 (2014/01/24) エラー時に??タも?力します? 283 throw new RuntimeException( errMsg ); 284 } 285 } 286 else { 287 if( !tempFile.delete() ) { 288 String errMsg = "??ファイルを削除できませんでした?" + tempFile + "]" + CR 289 + "data=[" + data.dataLine() + "]" + CR ; // 5.7.2.2 (2014/01/24) エラー時に??タも?力します? 290 throw new RuntimeException( errMsg ); 291 } 292 } 293 } 294 295 return (nextFlag) ? data : null ; 296 } 297 298 /** 299 * プロセスの処?果のレポ?ト表現を返します? 300 * 処??ログラ?、?力件数、?力件数などの??です? 301 * こ???をそのまま、標準?力に出すことで、結果レポ?トと出来るよ? 302 * 形式で出してください? 303 * 304 * @return 処?果のレポ?? 305 */ 306 public String report() { 307 String report = "[" + getClass().getName() + "]" + CR 308 + TAB + "Search File Count : " + inCount + CR 309 + TAB + "Key Find Count : " + findCount + CR 310 + TAB + "Key Change Count : " + cngCount ; 311 312 return report ; 313 } 314 315 /** 316 * こ?クラスの使用方法を返します? 317 * 318 * @return こ?クラスの使用方? 319 */ 320 public String usage() { 321 StringBuilder buf = new StringBuilder(); 322 323 buf.append( "Process_GrepChange は、上流から受け取っ?FileLineModelから、語句? ).append( CR ); 324 buf.append( "置換する?ChainProcess インターフェースの実?ラスです?" ).append( CR ); 325 buf.append( "Process_Grep との違いは、チェ?するファイルのコピ??キーワードが存在" ).append( CR ); 326 buf.append( "しなくと?作?することと、検索キーに正規表現が使えな???行置き換えが" ).append( CR ); 327 buf.append( "出来な?とです?" ).append( CR ); 328 buf.append( CR ); 329 buf.append( "keywordFile より、置換する語句を含?ーと値のペアー(タブ区?)を読取り? ).append( CR ); 330 buf.append( "対象とする語句を置換します?" ).append( CR ); 331 buf.append( "keywordFile に、タブが含まれな?や、?頭にタブが存在して?場合?? ).append( CR ); 332 buf.append( "そ?行を読み飛?します?また?区?タブ?何?存在しても構いません? ).append( CR ); 333 buf.append( "ただし?タブで区?た前(キー)と後ろ(値)は、trim() されます?で、スペ?ス" ).append( CR ); 334 buf.append( "が前後に存在して?場合?、ご注意く???" ).append( CR ); 335 buf.append( "置換文?値)は、\t と \n の特殊文字が使用できます?" ).append( CR ); 336 buf.append( "こ? GrepChange では、語句に、正規表現は使用できません。正規表現のキーワー? ).append( CR ); 337 buf.append( "?字?を?行???と置き換える場合?、Process_Grep を使用して下さ??" ).append( CR ); 338 buf.append( "こ?プログラ?は、上流から受け取っ?FileLineModel のファイルに対して? ).append( CR ); 339 buf.append( "置き換えた結果も?同じファイルにセーブします?" ).append( CR ); 340 buf.append( "??ファイルを保存したい場合?、予めバックア??を取得しておいてください? ).append( CR ); 341 buf.append( "-inEncode は、?力ファイルのエンコード指定になります?" ).append( CR ); 342 buf.append( "-outEncode は、?力ファイルのエンコードや、キーワードファイルのエンコー? ).append( CR ); 343 buf.append( "?になります?(keywordFile は、? 出力ファイルと同じエンコードです?)" ).append( CR ); 344 buf.append( "これら?エンコードが無??場合?、System.getProperty(\"file.encoding\") " ).append( CR ); 345 buf.append( "で求まる?を使用します?" ).append( CR ); 346 buf.append( CR ); 347 buf.append( "上流?ロセスでは、Name 属?として、?File』を持ち、?は、Fileオブジェク? ).append( CR ); 348 buf.append( "である、Process_FileSearch を使用するのが?便利です?それ以外?クラス? ).append( CR ); 349 buf.append( "使用する場合でも?Name属?と、File オブジェクトを持つ LineModel を受け渡? ).append( CR ); 350 buf.append( "できれば、使用可能です?" ).append( CR ); 351 buf.append( CR ); 352 buf.append( "引数??中に空白を含??合?、ダブルコー??ション(\"\") で括って下さ??" ).append( CR ); 353 buf.append( "引数??の ?』?前後には、空白は挟めません。??key=value の様に" ).append( CR ); 354 buf.append( "繋げてください? ).append( CR ); 355 buf.append( CR ).append( CR ); 356 357 buf.append( getArgument().usage() ).append( CR ); 358 359 return buf.toString(); 360 } 361 362 /** 363 * こ?クラスは、main メソ?から実行できません? 364 * 365 * @param args コマンド引数配? 366 */ 367 public static void main( final String[] args ) { 368 LogWriter.log( new Process_GrepChange().usage() ); 369 } 370 }