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.Arrays;
026 import java.util.Map ;
027 import java.util.LinkedHashMap ;
028 import java.util.regex.Pattern;
029 import java.util.regex.Matcher;
030
031 import java.io.File;
032 import java.io.PrintWriter;
033 import java.io.BufferedReader;
034 import java.io.IOException;
035
036 /**
037 * Process_Grep は、上流から受け取っã�?FileLineModelから、文字å?を見つけå?ã�?
038 * ChainProcess インターフェースの実è£?‚¯ラスですã?
039 *
040 * 正規表現の keyword を上流から受け取っã�?FileLineModel から検索しますã?
041 * 見つかった対象ファイルから、指定ã?æ–?—å?を置換するå?合ã?ã€?change ã�?
042 * -changeFile で、keyword を置換する文字å?を指定して下さã�??
043 * 置換する文字å?には、\t と \n の特殊文字が使用できますã?
044 *
045 * 処ç�?¯¾象はã€??常はã€?¼‘行づつ読み取りながら処ç�?‚’行いますã?存在チェãƒ?‚¯の場合ã?ã€?
046 * 見つかった時点で処ç�?‚’中止しますã?これは、該当ç®?‰€をピãƒ?‚¯アãƒ??するのではなくã?
047 * 存在してã�?‚‹かどã�?�‹を判断して、あれã?、下流に流すとã�?�†のが目çš?� からですã?
048 * keyword をã?改行を含ã‚?£規表現で、検索・置換するå?合ã?ã€?useBulkRead 属æ?ã‚?
049 * true に設定してください。これã?、å?力ファイルをä¸?‹¬して読み込みますã?
050 * -ignoreCase は、正規表現の検索時にキーの大æ–?—小文字を無視するよã�?�«æŒ?®šしますã?
051 * -notEquals は、結果(見つかればtrue)を反転(見つからなければtrue)しますã?
052 * これは、行単位ではなくã?ファイル単位に判定しますã?で、change æŒ?®šしたå?å�?
053 * でもã?対象行ã?、見つかった行ですã?ただしã?下流に対して、見つからなã�?
054 * 場合だけå?ç�?‚’継続させますã?
055 * -inEncode は、å?力ファイルのエンコード指定になりますã?
056 * -outEncode は、å?力ファイルのエンコードや、changeFileでæŒ?®šã?置換文字å?ファイルの
057 * エンコード指定になりますã?(changeFile は、å¿?�š 出力ファイルと同じエンコードですã?)
058 * これらã?エンコードが無æŒ?®šã?場合ã?、System.getProperty("file.encoding") で
059 * 求まるå?を使用しますã?
060 * -changeFile を使用することで、è¤?•°行ã?æ–?—å?に置換することが可能ですã?
061 * -outfile では、å?ç�?‚’行ったファイル名ä¸?¦§をセーブしますã?
062 *
063 * 上æµ?プロセスチェインのãƒ??タは上流から渡されますã?)からのLineModel の
064 * ファイルオブジェクトよりã?æŒ?®šã?æ–?—å?が含まれてã�?‚‹か検索しますã?
065 * 上流ã?ロセスでは、Name 属æ?として、ã?File』を持ち、å?は、Fileオブジェクãƒ?
066 * である、Process_FileSearch を使用するのがã?便利ですã?それ以外ã?クラスã‚?
067 * 使用する場合でもã?Name属æ?と、File オブジェクトを持つ LineModel を受け渡ã�?
068 * できれば、使用可能ですã?
069 *
070 * 引数æ–?—å?中に空白を含ã‚??合ã?、ダブルコーãƒ??ション("") で括って下さã�??
071 * 引数æ–?—å?の ã€?』ã?前後には、空白は挟めません。å¿?�šã€?key=value の様に
072 * 繋げてくださいã€?
073 *
074 * @og.formSample
075 * Process_Grep -keyword=検索æ–?—å? -ignoreCase=true -outfile=OUTFILE -encode=UTF-8
076 *
077 * -keyword=キーワーãƒ? ?š検索する語句
078 * [-ignoreCase=大æ–?—小文å?] ?š検索時に大æ–?—小文字を区別しなã�?true)かどã�?�‹(初期値:区別する[false])
079 * [-notEquals=判定結果の反転] ?š判定結果を反転させã‚?true)かどã�?�‹(初期値:反転させない[false])
080 * [-inEncode=入力エンコーãƒ?] ?šå?力ファイルのエンコードタイãƒ?
081 * [-outEncode=出力エンコード] ?šå?力ファイルã‚?½®換ファイルのエンコードタイãƒ?
082 * [-change=置換文字å? ] ??change="ABCD" \t ã‚?\n などの特殊文字が使用できますã?
083 * [-changeFile=置換ファイル ] ??changeFile=change.txt こã?ファイルの記述すべてと置換しますã?
084 * -change とã€?changeFile は、同時にæŒ?®šできませんã€?
085 * 置換機è?使用時ã?、å¿?�š、_backup とã�?�†ファイルが作æ?されますã?
086 * [-insert=[CHANGE/BEFORE/AFTER] ] : 置換でなく挿入する場合ã?位置を指定しまã�?初期値:CHANGE)
087 * スペã?スで区åˆ?�£て数字を記述すると、挿入位置にオフセãƒ?ƒˆできますã?
088 * [-delete=[false/true] ] : 置換でなく削除しまã�?初期値:false)
089 * [-useBackup=[false/true] ] ?štrueは、backupファイルを作æ?しまã�?初期値:false)
090 * [-useBulkRead=[false/true]] ?štrueは、å?力ファイルをä¸?‹¬読込しまã�?初期値:false)
091 * [-display=[false/true] ] ?štrueは、検索状況を表示しまã�?初期値:false)
092 * [-debug=[false/true] ] ?šデバッグæƒ??を標準å?力に表示する(true)かしなã�?false)ã�?初期値:false[表示しない])
093 *
094 * @version 4.0
095 * @author Kazuhiko Hasegawa
096 * @since JDK5.0,
097 */
098 public class Process_Grep extends AbstractProcess implements ChainProcess {
099 private static final String[] INSERT_LIST = new String[] { "CHANGE","BEFORE","AFTER" };
100
101 private Pattern pattern = null;
102 private String keyword = null;
103 private boolean ignoreCase = false;
104 private boolean notEquals = false;
105 private String inEncode = null;
106 private String outEncode = null;
107 private String change = null;
108 private String insert = "CHANGE"; // "CHANGE","BEFORE","AFTER" のどれか
109 private int insOffset = 0; // "BEFORE","AFTER" 時ã?オフセãƒ?ƒˆ
110 private boolean useBackup = false;
111 private boolean useBulkRead = false; // 4.0.1.0 (2007/12/14)
112 private boolean delete = false;
113 private boolean display = false;
114 private boolean debug = false; // 5.1.2.0 (2010/01/01)
115
116 private int inCount = 0;
117 private int findCount = 0;
118 private int cngCount = 0;
119
120 private static final Map<String,String> mustProparty ; // ?»プロパティ?½å¿??チェãƒ?‚¯用 Map
121 private static final Map<String,String> usableProparty ; // ?»プロパティ?½整合æ?チェãƒ?‚¯ Map
122
123 static {
124 mustProparty = new LinkedHashMap<String,String>();
125 mustProparty.put( "keyword", "検索する語句(å¿??)" );
126
127 usableProparty = new LinkedHashMap<String,String>();
128 usableProparty.put( "ignoreCase", "検索時に大æ–?—小文字を区別しなã�?true)かどã�?�‹ã€? +
129 CR + "(初期値:区別する[false])" );
130 usableProparty.put( "notEquals", "検索時に判定結果を反転させã‚?true)かどã�?�‹ã€? +
131 CR + "(初期値:反転させない[false])" );
132 usableProparty.put( "inEncode", "入力ファイルのエンコードタイãƒ? );
133 usableProparty.put( "outEncode", "出力ファイルã‚?½®換ファイルのエンコードタイãƒ? );
134 usableProparty.put( "change", "置換文字å? ä¾? -change=\"ABCD\" \\t ã‚?\\n などの特殊文字が使用できますã?" );
135 usableProparty.put( "changeFile", "置換文字å?ファイル ä¾? -changeFile=change.txt" +
136 CR + "-change とã€?changeFile は、同時にæŒ?®šできませんã€? +
137 CR + "置換機è?使用時ã?、å¿?�š、_backup とã�?�†ファイルが作æ?されますã?" );
138 usableProparty.put( "insert", "[CHANGE/BEFORE/AFTER]:置換でなく挿入する場合ã?位置を指定しまã�?初期値:CHANGE)" +
139 CR + "スペã?スで区åˆ?�£て数字を記述すると、挿入位置にオフセãƒ?ƒˆできますã?" );
140 usableProparty.put( "delete", "[false/true]:trueは、置換でなく削除しまã�?初期値:false)" );
141 usableProparty.put( "useBackup", "[false/true]:trueは、backupファイルを作æ?しまã�?初期値:false)" );
142 usableProparty.put( "useBulkRead", "[false/true]:trueは、å?力ファイルをä¸?‹¬読込しまã�?初期値:false)" );
143 usableProparty.put( "display", "[false/true]:trueは、検索状況を表示しまã�?初期値:false)" );
144 usableProparty.put( "debug", "ãƒ?ƒ�ãƒ?‚°æƒ??を標準å?力に表示する(true)かしなã�?false)ã�? +
145 CR + "(初期値:false:表示しなã�?" );
146 }
147
148 /**
149 * ãƒ?ƒ•ォルトコンストラクターã€?
150 * こã?クラスは、動çš?½œæ?されますã?ãƒ?ƒ•ォルトコンストラクターでã€?
151 * super クラスに対して、å¿?¦�な初期化を行っておきますã?
152 *
153 */
154 public Process_Grep() {
155 super( "org.opengion.fukurou.process.Process_Grep",mustProparty,usableProparty );
156 }
157
158 /**
159 * プロセスの初期化を行いますã?初めにä¸?º¦ã�?�‘、呼び出されますã?
160 * 初期処ç�?ファイルオープンã€?¼¤?¢オープンç?に使用しますã?
161 *
162 * @param paramProcess ãƒ??タベã?スの接続å?æƒ??などを持ってã�?‚‹オブジェクãƒ?
163 */
164 public void init( final ParamProcess paramProcess ) {
165 Argument arg = getArgument();
166
167 keyword = arg.getProparty("keyword");
168 ignoreCase = arg.getProparty("ignoreCase" ,ignoreCase);
169 notEquals = arg.getProparty("notEquals" ,notEquals);
170 inEncode = arg.getProparty("inEncode" ,System.getProperty("file.encoding"));
171 outEncode = arg.getProparty("outEncode" ,System.getProperty("file.encoding"));
172 useBackup = arg.getProparty("useBackup" ,useBackup);
173 useBulkRead = arg.getProparty("useBulkRead" ,useBulkRead); // 4.0.1.0 (2007/12/14)
174 delete = arg.getProparty("delete" ,delete );
175 insert = arg.getProparty("insert" ,insert );
176 change = arg.getFileProparty( "change","changeFile",outEncode,false );
177 display = arg.getProparty("display" ,display);
178 debug = arg.getProparty( "debug" ,debug ); // 5.1.2.0 (2010/01/01)
179 // if( debug ) { println( arg.toString() ); } // 5.7.3.0 (2014/02/07) ãƒ?ƒ�ãƒ?‚°æƒ??
180
181 if( change != null ) {
182 int adrs = insert.indexOf( ' ' ); // オフセãƒ?ƒˆ数字ã?有無
183 if( adrs > 0 ) {
184 insOffset = Integer.parseInt( insert.substring( adrs+1 ) );
185 insert = insert.substring( 0,adrs );
186 }
187
188 boolean isOK = false;
189 for( int i=0; i<INSERT_LIST.length; i++ ) {
190 if( insert.equalsIgnoreCase( INSERT_LIST[i] ) ) {
191 isOK = true; break;
192 }
193 }
194 if( !isOK ) {
195 String errMsg = "insert はã€? + Arrays.toString( INSERT_LIST )
196 + " からæŒ?®šしてくださいã€? + CR
197 + "-insert=[" + insert + "]" ;
198 throw new RuntimeException( errMsg );
199 }
200
201 change = StringUtil.replace( change,"\\n",CR );
202 change = StringUtil.replace( change,"\\t","\t" );
203 }
204
205 if( delete ) { change = ""; } // 削除はã€?" æ–?—å?と置換しますã?
206
207 if( ignoreCase ) {
208 pattern = Pattern.compile( keyword,Pattern.CASE_INSENSITIVE );
209 }
210 else {
211 pattern = Pattern.compile( keyword );
212 }
213 }
214
215 /**
216 * プロセスの終äº?‚’行いますã?æœ?¾Œにä¸?º¦ã�?�‘、呼び出されますã?
217 * 終äº??ç�?ファイルクローズã€?¼¤?¢クローズç?に使用しますã?
218 *
219 * @param isOK トã?タルで、OKã�?�£たかどã�?�‹[true:成功/false:失敗]
220 */
221 public void end( final boolean isOK ) {
222 // ここでは処ç�?‚’行いませんã€?
223 }
224
225 /**
226 * 引数の LineModel をå?ç�?�™るメソãƒ?ƒ‰ですã?
227 * 変換処ç�?¾Œã? LineModel を返しますã?
228 * 後続å?ç�?‚’行わなã�??å�?ãƒ??タのフィルタリングを行う場å�?はã€?
229 * null ãƒ??タを返しますã?つまりã?null ãƒ??タは、後続å?ç�?‚’行わなã�?
230 * フラグの代わりにも使用してã�?�¾すã?
231 * なおã?変換処ç�?¾Œã? LineModel と、オリジナルの LineModel がã?
232 * 同ä¸?�‹、コピã?(クローン)かã?、各処ç�?ƒ¡ソãƒ?ƒ‰å†?�§決めてã�?�¾すã?
233 * ドキュメントに明記されてã�?�ªã�??合ã?、副作用が問題になるå?合ã?ã€?
234 * å�??ç�?�”とに自åˆ?�§コピã?(クローン)して下さã�??
235 *
236 * @og.rev 4.0.1.0 (2007/12/14) ファイルのä¸?‹¬処ç�?¯¾応ã?
237 * @og.rev 5.7.2.2 (2014/01/24) エラー時にãƒ??タもå?力しますã?
238 *
239 * @param data オリジナルのLineModel
240 *
241 * @return 処ç�?¤‰換後ã?LineModel
242 */
243 public LineModel action( final LineModel data ) {
244 inCount++ ;
245
246 final FileLineModel fileData ;
247 if( data instanceof FileLineModel ) {
248 fileData = (FileLineModel)data ;
249 }
250 else {
251 String errMsg = "ãƒ??タã�?FileLineModel オブジェクトではありませんã€? + CR ;
252 throw new RuntimeException( errMsg );
253 }
254
255 File file = fileData.getFile() ;
256 if( ! file.isFile() ) {
257 if( display ) { println( data.dataLine() ); } // 5.1.2.0 (2010/01/01) display の条件変更
258 return data;
259 }
260
261 final boolean isFind ;
262 try {
263 String fileLine = null;
264 int firstLineNo = -1;
265 if( useBulkRead ) { fileLine = findKeywordAsBulk( file ); }
266 else { firstLineNo = findKeyword( file ); }
267
268 isFind = ( fileLine != null ) || ( firstLineNo >= 0 ) ;
269
270 // 置換å?ç�?ただしã?見つかったときã?み実è¡?
271 if( change != null && isFind ) {
272 // 入力ファイルは、オリジナル_backup ファイルとする。過去のファイルを削除
273 File inFile = new File( file.getPath() + "_backup" );
274 if( inFile.exists() && !inFile.delete() ) {
275 String errMsg = "過去のBKUPファイルを削除できませんでしたã€?" + inFile + "]" + CR
276 + "data=[" + data.dataLine() + "]" + CR ; // 5.7.2.2 (2014/01/24) エラー時にãƒ??タもå?力しますã?
277 throw new RuntimeException( errMsg );
278 }
279
280 // オリジナルのファイルをã?_backup ファイル名に先に変換するã€?
281 File fromFile = new File( file.getPath() );
282 if( !fromFile.renameTo( inFile ) ) {
283 String errMsg = "æ‰?®šã?ファイルをリネã?ãƒ?�§きませんでしたã€?" + fromFile + "]" + CR
284 + "data=[" + data.dataLine() + "]" + CR ; // 5.7.2.2 (2014/01/24) エラー時にãƒ??タもå?力しますã?
285 throw new RuntimeException( errMsg );
286 }
287
288 // 変換処ç�?本ä½?
289 if( useBulkRead ) { changeKeywordAsBulk( fileLine,file ); }
290 else { changeKeyword( inFile,file,firstLineNo ); }
291
292 // backup を使わなã�??合ã?、削除するã€?
293 // 4.0.0.0 (2007/11/29) 入れ子if の統å�?
294 if( ! useBackup && !inFile.delete() ) {
295 String errMsg = "æ‰?®šã?ファイルを削除できませんでしたã€?" + inFile + "]" + CR
296 + "data=[" + data.dataLine() + "]" + CR ; // 5.7.2.2 (2014/01/24) エラー時にãƒ??タもå?力しますã?
297 throw new RuntimeException( errMsg );
298 }
299 }
300 }
301 catch ( RuntimeException ex ) {
302 String errMsg = "処ç�?¸にエラーが発生しましたã€?" + data.getRowNo() + "]件目" + CR
303 // + data.toString() ;
304 + "data=[" + data.dataLine() + "]" + CR ; // 5.7.2.2 (2014/01/24) エラー時にãƒ??タもå?力しますã?
305 throw new RuntimeException( errMsg,ex );
306 }
307
308 if( display && ( notEquals ^ isFind ) ) { println( data.dataLine() ); } // 5.1.2.0 (2010/01/01) display の条件変更
309 return ( notEquals ^ isFind ) ? data : null ;
310 }
311
312 /**
313 * キーワードが存在してã�?‚‹かどã�?�‹をチェãƒ?‚¯しますã?
314 * ここではã€?¼‘行づつ読み取りながら、最初に見つかった時点で制御を返しますã?
315 * よって、è¤?•°行にまたがã‚?keyword でのマッチングは出来ませんがã?大きな
316 * ファイル等での検索には、効çŽ?š„ですã?
317 *
318 * @og.rev 4.0.1.0 (2007/12/14) 新規追åŠ?
319 *
320 * @param file 検索å…??ファイルオブジェクãƒ?
321 *
322 * @return æœ??に見つかった行番号(見つからなければã€?1 を返す)
323 */
324 private int findKeyword( final File file ) {
325 BufferedReader reader = null;
326
327 int firstLineNo = -1;
328 try {
329 reader = FileUtil.getBufferedReader( file,inEncode );
330 String line ;
331 int lineNo = 0;
332 while((line = reader.readLine()) != null) {
333 lineNo++ ;
334 Matcher mach = pattern.matcher( line );
335 if( mach.find() ) {
336 if( debug ) {
337 String buf = "DEBUG:\t" + file.getPath() + "(" + lineNo + "): " + line ;
338 println( buf );
339 }
340 firstLineNo = lineNo;
341 break;
342 }
343 }
344 }
345 catch ( IOException ex ) {
346 String errMsg = "ファイル読取エラーが発生しましたã€?" + file.getPath() + "]" ;
347 throw new RuntimeException( errMsg,ex );
348 }
349 finally {
350 Closer.ioClose( reader );
351 }
352
353 return firstLineNo;
354 }
355
356 /**
357 * キーワードが存在してã�?‚‹かどã�?�‹をチェãƒ?‚¯しますã?
358 * ここでは、ファイルをすべて読み取ってから、チェãƒ?‚¯しますã?
359 * よって、è¤?•°行にまたがã‚?keyword でのマッチングが可能ですã?
360 *
361 * @og.rev 4.0.1.0 (2007/12/14) 新規追åŠ?
362 *
363 * @param file 検索å…??ファイルオブジェクãƒ?
364 *
365 * @return 検索å…??ファイルのæ–?—å?化情報(ただしã?見つからなければ、null)
366 */
367 private String findKeywordAsBulk( final File file ) {
368
369 boolean isFind = false;
370
371 FileString sf = new FileString();
372 sf.setFilename( file.getPath() );
373 sf.setEncode( inEncode );
374 String line = sf.getValue();
375
376 Matcher mach = pattern.matcher( line );
377 if( mach.find() ) {
378 if( debug ) { println( "DEBUG:\t" + file.getPath() ); }
379 isFind = true;
380 }
381
382 return ( isFind ) ? line : null;
383 }
384
385 /**
386 * キーワードをæŒ?®šã?æ–?—å?に置き換えますã?
387 * useBackup 属æ?に true を指定したå?合ã?置き換え後ã?、backup ファイルはã€?
388 * オリジナル_backup とã�?�†名称に変わりますã?
389 * ここではã€?¼‘行づつ読み取りながら、変換処ç�?‚’行いますã?
390 * よって、è¤?•°行にまたがã‚?keyword でのマッチングは出来ませんがã?大きな
391 * ファイル等での置換でもã?メモリの使用量ã?抑えられますã?
392 *
393 * @og.rev 4.0.1.0 (2007/12/14) 置換å?ç�?‚’独立させますã?
394 *
395 * @param inFile 検索å…??入力ファイルオブジェクãƒ?
396 * @param outFile 変換後ã?出力ファイルオブジェクãƒ?
397 * @param firstLineNo キーワードが存在した場合ã?æœ??の行番号
398 */
399 private void changeKeyword( final File inFile,final File outFile,final int firstLineNo ) {
400
401 BufferedReader reader = FileUtil.getBufferedReader( inFile,inEncode );
402 PrintWriter writer = FileUtil.getPrintWriter( outFile,outEncode );
403
404 String line = null;
405 try {
406 int lineNo = 0;
407 while((line = reader.readLine()) != null) {
408 lineNo++ ;
409 if( lineNo >= firstLineNo ) {
410 Matcher mach = pattern.matcher( line );
411
412 String chnStr = null;
413 if( "CHANGE".equals( insert ) ) {
414 chnStr = strChange( mach );
415 }
416 else if( "BEFORE".equals( insert ) ) {
417 chnStr = strBefore( line,mach );
418 }
419 else if( "AFTER".equals( insert ) ) {
420 chnStr = strAfter( line,mach );
421 }
422
423 if( chnStr != null ) {
424 line = chnStr;
425 cngCount++ ; // 変換されれã? カウンãƒ?
426 }
427 }
428 writer.println( line ); // readLine() してるã?で、最後に改行がå¿?¦�ã?
429 }
430 }
431 catch ( IOException ex ) {
432 String errMsg = "処ç�?¸にエラーが発生しましたã€?" + line + "]" ;
433 throw new RuntimeException( errMsg,ex );
434 }
435 finally {
436 Closer.ioClose( reader );
437 Closer.ioClose( writer );
438 }
439 }
440 /**
441 * キーワードをæŒ?®šã?æ–?—å?に置き換えますã?
442 * useBackup 属æ?に true を指定したå?合ã?置き換え後ã?、backup ファイルはã€?
443 * オリジナル_backup とã�?�†名称に変わりますã?
444 * ここでは、ファイルをすべて読み取ってから、チェãƒ?‚¯しますã?
445 * よって、è¤?•°行にまたがã‚?keyword でのマッチングが可能ですã?
446 *
447 * @og.rev 4.0.1.0 (2007/12/14) 置換å?ç�?‚’独立させますã?
448 *
449 * @param fileLine 検索å…??行文字å?
450 * @param outFile 出力ファイルオブジェクãƒ?
451 */
452 private void changeKeywordAsBulk( final String fileLine,final File outFile ) {
453 PrintWriter writer = FileUtil.getPrintWriter( outFile,outEncode );
454
455 String line = fileLine ;
456 try {
457 Matcher mach = pattern.matcher( line );
458
459 String chnStr = null;
460 if( "CHANGE".equals( insert ) ) {
461 chnStr = strChange( mach );
462 }
463 else if( "BEFORE".equals( insert ) ) {
464 chnStr = strBefore( line,mach );
465 }
466 else if( "AFTER".equals( insert ) ) {
467 chnStr = strAfter( line,mach );
468 }
469
470 if( chnStr != null ) {
471 line = chnStr;
472 cngCount++ ; // 変換されれã? カウンãƒ?
473 }
474
475 writer.print( line ); // 注意:改行コードã?、不è¦?
476 }
477 catch ( RuntimeException ex ) {
478 String errMsg = "処ç�?¸にエラーが発生しましたã€?" + outFile.getPath() + "]" ;
479 throw new RuntimeException( errMsg,ex );
480 }
481 finally {
482 Closer.ioClose( writer );
483 }
484 }
485
486 /**
487 * insert がã?"CHANGE" の場合ã?処ç�?µ�果を求めますã?
488 * 変換しなかったå?合ã?、null を返しますã?
489 * これは、変換カウントを算å?する為のフラグ代わりに使用してã�?�¾すã?
490 *
491 * @param mach キーワードã?正規表現
492 *
493 * @return 変換結果(対象行で無ã�??合ã?、null)
494 */
495 private String strChange( final Matcher mach ) {
496 String line = null;
497 if( mach.find() ) {
498 line = mach.replaceAll( change );
499 }
500 return line ;
501 }
502
503 /**
504 * insert がã?"BEFORE" の場合ã?処ç�?µ�果を求めますã?
505 * 変換しなかったå?合ã?、null を返しますã?
506 * これは、変換カウントを算å?する為のフラグ代わりに使用してã�?�¾すã?
507 *
508 * @param line 検索è¡?
509 * @param mach キーワードã?正規表現
510 *
511 * @return 変換結果(対象行で無ã�??合ã?、null)
512 */
513 private String strBefore( final String line , final Matcher mach ) {
514 boolean isChng = false;
515 StringBuilder buf = new StringBuilder( line.length() );
516 int indx = 0;
517 while( mach.find() ) {
518 isChng = true;
519 int strt = mach.start() + insOffset;
520 buf.append( line.substring( indx,strt ) );
521 buf.append( change );
522 indx = strt;
523 }
524
525 String rtn = null;
526 if( isChng ) {
527 buf.append( line.substring( indx ) );
528 rtn = buf.toString();
529 }
530
531 return rtn ;
532 }
533
534 /**
535 * insert がã?"AFTER" の場合ã?処ç�?µ�果を求めますã?
536 * 変換しなかったå?合ã?、null を返しますã?
537 * これは、変換カウントを算å?する為のフラグ代わりに使用してã�?�¾すã?
538 *
539 * @param line 検索è¡?
540 * @param mach キーワードã?正規表現
541 *
542 * @return 変換結果(対象行で無ã�??合ã?、null)
543 */
544 private String strAfter( final String line , final Matcher mach ) {
545 boolean isChng = false;
546 StringBuilder buf = new StringBuilder( line.length() );
547 int indx = 0;
548 while( mach.find() ) {
549 isChng = true;
550 int end = mach.end() + insOffset;
551 buf.append( line.substring( indx,end ) );
552 buf.append( change );
553 indx = end;
554 }
555 String rtn = null;
556 if( isChng ) {
557 buf.append( line.substring( indx ) );
558 rtn = buf.toString();
559 }
560
561 return rtn ;
562 }
563
564 /**
565 * プロセスの処ç�?µ�果のレポã?ト表現を返しますã?
566 * 処ç�??ログラãƒ?��、å?力件数、å?力件数などのæƒ??ですã?
567 * こã?æ–?—å?をそのまま、標準å?力に出すことで、結果レポã?トと出来るよã�?�ª
568 * 形式で出してくださいã€?
569 *
570 * @return 処ç�?µ�果のレポã?ãƒ?
571 */
572 public String report() {
573 if( findCount < cngCount ) { findCount = cngCount; }
574
575 String report = "[" + getClass().getName() + "]" + CR
576 + TAB + "Search Keyword : " + keyword + CR
577 + TAB + "Search File Count : " + inCount + CR
578 + TAB + "Key Find Count : " + findCount + CR
579 + TAB + "Key Change Count : " + cngCount ;
580
581 return report ;
582 }
583
584 /**
585 * こã?クラスの使用方法を返しますã?
586 *
587 * @return こã?クラスの使用方æ³?
588 */
589 public String usage() {
590 StringBuilder buf = new StringBuilder();
591
592 buf.append( "Process_Grep は、上流から受け取っã�?FileLineModelから、文字å?を見つけå?ã�? ).append( CR );
593 buf.append( "ChainProcess インターフェースの実è£?‚¯ラスですã?" ).append( CR );
594 buf.append( CR );
595 buf.append( "正規表現の keyword を上流から受け取っã�?FileLineModel から検索しますã?" ).append( CR );
596 buf.append( "見つかった対象ファイルから、指定ã?æ–?—å?を置換するå?合ã?ã€?change ã�? ).append( CR );
597 buf.append( "-changeFile で、keyword を置換する文字å?を指定して下さã�??" ).append( CR );
598 buf.append( "置換する文字å?には、\t と \n の特殊文字が使用できますã?" ).append( CR );
599 buf.append( CR );
600 buf.append( "処ç�?¯¾象はã€??常はã€?¼‘行づつ読み取りながら処ç�?‚’行いますã?存在チェãƒ?‚¯の場合ã?ã€? ).append( CR );
601 buf.append( "見つかった時点で処ç�?‚’中止しますã?これは、該当ç®?‰€をピãƒ?‚¯アãƒ??するのではなくã?" ).append( CR );
602 buf.append( "存在してã�?‚‹かどã�?�‹を判断して、あれã?、下流に流すとã�?�†のが目çš?� からですã?" ).append( CR );
603 buf.append( "keyword をã?改行を含ã‚?£規表現で、検索・置換するå?合ã?ã€?useBulkRead 属æ?ã‚? ).append( CR );
604 buf.append( "true に設定してください。これã?、å?力ファイルをä¸?‹¬して読み込みますã?" ).append( CR );
605 buf.append( "-ignoreCase は、検索時にキーの大æ–?—小文字を無視するよã�?�«æŒ?®šしますã?" ).append( CR );
606 buf.append( "-notEquals は、結果(見つかればtrue)を反転(見つからなければtrue)しますã?" ).append( CR );
607 buf.append( "これは、行単位ではなくã?ファイル単位に判定しますã?で、change æŒ?®šしたå?å�? ).append( CR );
608 buf.append( "でもã?対象行ã?、見つかった行ですã?ただしã?下流に対して、見つからなã�? ).append( CR );
609 buf.append( "場合だけå?ç�?‚’継続させますã?" ).append( CR );
610 buf.append( "-inEncode は、å?力ファイルのエンコード指定になりますã?" ).append( CR );
611 buf.append( "-outEncode は、å?力ファイルのエンコードや、changeFileでæŒ?®šã?置換文字å?" ).append( CR );
612 buf.append( "ファイルのエンコード指定になりますã?(changeFile は、å¿?�š 出力ファイルと)" ).append( CR );
613 buf.append( "同じエンコードですã?" ).append( CR );
614 buf.append( "これらã?エンコードが無æŒ?®šã?場合ã?、System.getProperty(\"file.encoding\") " ).append( CR );
615 buf.append( "で求まるå?を使用しますã?" ).append( CR );
616 buf.append( "-changeFile を使用することで、è¤?•°行ã?æ–?—å?に置換することが可能ですã?" ).append( CR );
617 buf.append( CR );
618 buf.append( "上æµ?プロセスチェインのãƒ??タは上流から渡されますã?)からのLineModel の" ).append( CR );
619 buf.append( "ファイルオブジェクトよりã?æŒ?®šã?æ–?—å?が含まれてã�?‚‹か検索しますã?" ).append( CR );
620 buf.append( "上流ã?ロセスでは、Name 属æ?として、ã?File』を持ち、å?は、Fileオブジェクãƒ? ).append( CR );
621 buf.append( "である、Process_FileSearch を使用するのがã?便利ですã?それ以外ã?クラスã‚? ).append( CR );
622 buf.append( "使用する場合でもã?Name属æ?と、File オブジェクトを持つ LineModel を受け渡ã�? ).append( CR );
623 buf.append( "できれば、使用可能ですã?" ).append( CR );
624 buf.append( CR );
625 buf.append( "引数æ–?—å?中に空白を含ã‚??合ã?、ダブルコーãƒ??ション(\"\") で括って下さã�??" ).append( CR );
626 buf.append( "引数æ–?—å?の ã€?』ã?前後には、空白は挟めません。å¿?�šã€?key=value の様に" ).append( CR );
627 buf.append( "繋げてくださいã€? ).append( CR );
628 buf.append( CR ).append( CR );
629
630 buf.append( getArgument().usage() ).append( CR );
631
632 return buf.toString();
633 }
634
635 /**
636 * こã?クラスは、main メソãƒ?ƒ‰から実行できませんã€?
637 *
638 * @param args コマンド引数配å?
639 */
640 public static void main( final String[] args ) {
641 LogWriter.log( new Process_Grep().usage() );
642 }
643 }