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=[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",           "[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    
180                    if( change != null ) {
181                            int adrs = insert.indexOf( ' ' );       // オフセ?数字?有無
182                            if( adrs > 0 ) {
183                                    insOffset = Integer.parseInt( insert.substring( adrs+1 ) );
184                                    insert    = insert.substring( 0,adrs );
185                            }
186    
187                            boolean isOK = false;
188                            for( int i=0; i<INSERT_LIST.length; i++ ) {
189                                    if( insert.equalsIgnoreCase( INSERT_LIST[i] ) ) {
190                                            isOK = true; break;
191                                    }
192                            }
193                            if( !isOK ) {
194                                    String errMsg = "insert は? + Arrays.toString( INSERT_LIST )
195                                                                            + " から?してください? + CR
196                                                                            + "-insert=[" + insert + "]" ;
197                                    throw new RuntimeException( errMsg );
198                            }
199    
200                            change = StringUtil.replace( change,"\\n",CR );
201                            change = StringUtil.replace( change,"\\t","\t" );
202                    }
203    
204                    if( delete ) { change = ""; }   // 削除は?" ??と置換します?
205    
206                    if( ignoreCase ) {
207                            pattern = Pattern.compile( keyword,Pattern.CASE_INSENSITIVE );
208                    }
209                    else {
210                            pattern = Pattern.compile( keyword );
211                    }
212            }
213    
214            /**
215             * プロセスの終?行います??に??、呼び出されます?
216             * 終???ファイルクローズ??クローズ?に使用します?
217             *
218             * @param   isOK ト?タルで、OK?たかど?[true:成功/false:失敗]
219             */
220            public void end( final boolean isOK ) {
221                    // ここでは処?行いません?
222            }
223    
224            /**
225             * 引数の LineModel を??るメソ?です?
226             * 変換処?? LineModel を返します?
227             * 後続??行わな?????タのフィルタリングを行う場?は?
228             * null ??タを返します?つまり?null ??タは、後続??行わな?
229             * フラグの代わりにも使用して?す?
230             * なお?変換処?? LineModel と、オリジナルの LineModel が?
231             * 同?、コピ?(クローン)か?、各処?ソ??決めて?す?
232             * ドキュメントに明記されて???合?、副作用が問題になる?合??
233             * ???とに自?コピ?(クローン)して下さ??
234             *
235             * @og.rev 4.0.1.0 (2007/12/14) ファイルの?処?応?
236             * @og.rev 5.7.2.2 (2014/01/24) エラー時に??タも?力します?
237             *
238             * @param       data    オリジナルのLineModel
239             *
240             * @return      処?換後?LineModel
241             */
242            public LineModel action( final LineModel data ) {
243                    inCount++ ;
244    
245                    final FileLineModel fileData ;
246                    if( data instanceof FileLineModel ) {
247                            fileData = (FileLineModel)data ;
248                    }
249                    else {
250                            String errMsg = "??タ?FileLineModel オブジェクトではありません? + CR ;
251                            throw new RuntimeException( errMsg );
252                    }
253    
254                    File file = fileData.getFile() ;
255                    if( ! file.isFile() ) {
256                            if( display ) { println( data.dataLine() ); }           // 5.1.2.0 (2010/01/01) display の条件変更
257                            return data;
258                    }
259    
260                    final boolean isFind ;
261                    try {
262                            String fileLine = null;
263                            int firstLineNo = -1;
264                            if( useBulkRead ) { fileLine    = findKeywordAsBulk( file ); }
265                            else                      { firstLineNo = findKeyword( file ); }
266    
267                            isFind = ( fileLine != null ) || ( firstLineNo >= 0 ) ;
268    
269                            // 置換??ただし?見つかったとき?み実?
270                            if( change != null && isFind ) {
271                                    // 入力ファイルは、オリジナル_backup ファイルとする。過去のファイルを削除
272                                    File inFile = new File( file.getPath() + "_backup" );
273                                    if( inFile.exists() && !inFile.delete() ) {
274                                            String errMsg = "??ファイルを削除できませんでした?" + inFile + "]" + CR
275                                                                    +       "data=[" + data.dataLine() + "]" + CR ;         // 5.7.2.2 (2014/01/24) エラー時に??タも?力します?
276                                            throw new RuntimeException( errMsg );
277                                    }
278    
279                                    // オリジナルのファイルを?_backup ファイル名に先に変換する?
280                                    File fromFile = new File( file.getPath() );
281                                    if( !fromFile.renameTo( inFile ) ) {
282                                            String errMsg = "??ファイルをリネ??きませんでした?" + fromFile + "]" + CR
283                                                                    +       "data=[" + data.dataLine() + "]" + CR ;         // 5.7.2.2 (2014/01/24) エラー時に??タも?力します?
284                                            throw new RuntimeException( errMsg );
285                                    }
286    
287                                    // 変換処?本?
288                                    if( useBulkRead ) { changeKeywordAsBulk( fileLine,file ); }
289                                    else                      { changeKeyword( inFile,file,firstLineNo ); }
290    
291                                    // backup を使わな??合?、削除する?
292                                    // 4.0.0.0 (2007/11/29) 入れ子if の統?
293                                    if( ! useBackup && !inFile.delete() ) {
294                                            String errMsg = "??ファイルを削除できませんでした?" + inFile + "]" + CR
295                                                                    +       "data=[" + data.dataLine() + "]" + CR ;         // 5.7.2.2 (2014/01/24) エラー時に??タも?力します?
296                                            throw new RuntimeException( errMsg );
297                                    }
298                            }
299                    }
300                    catch ( RuntimeException ex ) {
301                            String errMsg = "処?にエラーが発生しました?" + data.getRowNo() + "]件目" + CR
302    //                                              + data.toString() ;
303                                                    +       "data=[" + data.dataLine() + "]" + CR ;         // 5.7.2.2 (2014/01/24) エラー時に??タも?力します?
304                            throw new RuntimeException( errMsg,ex );
305                    }
306    
307                    if( display && ( notEquals ^ isFind ) ) { println( data.dataLine() ); }         // 5.1.2.0 (2010/01/01) display の条件変更
308                    return ( notEquals ^ isFind ) ? data : null ;
309            }
310    
311            /**
312             * キーワードが存在して?かど?をチェ?します?
313             * ここでは?行づつ読み取りながら、最初に見つかった時点で制御を返します?
314             * よって、?行にまたが?keyword でのマッチングは出来ませんが?大きな
315             * ファイル等での検索には、効?です?
316             *
317             * @og.rev 4.0.1.0 (2007/12/14) 新規追?
318             *
319             * @param       file    検索??ファイルオブジェク?
320             *
321             * @return      ??に見つかった行番号(見つからなければ?1 を返す)
322             */
323            private int findKeyword( final File file ) {
324                    BufferedReader reader = null;
325    
326                    int firstLineNo = -1;
327                    try {
328                            reader = FileUtil.getBufferedReader( file,inEncode );
329                            String line ;
330                            int lineNo = 0;
331                            while((line = reader.readLine()) != null) {
332                                    lineNo++ ;
333                                    Matcher mach = pattern.matcher( line );
334                                    if( mach.find() ) {
335                                            if( debug ) {
336                                                    String buf = "DEBUG:\t" + file.getPath() + "(" + lineNo + "): " + line ;
337                                                    println( buf );
338                                            }
339                                            firstLineNo = lineNo;
340                                            break;
341                                    }
342                            }
343                    }
344                    catch ( IOException ex ) {
345                            String errMsg = "ファイル読取エラーが発生しました?" + file.getPath() + "]" ;
346                            throw new RuntimeException( errMsg,ex );
347                    }
348                    finally {
349                            Closer.ioClose( reader );
350                    }
351    
352                    return firstLineNo;
353            }
354    
355            /**
356             * キーワードが存在して?かど?をチェ?します?
357             * ここでは、ファイルをすべて読み取ってから、チェ?します?
358             * よって、?行にまたが?keyword でのマッチングが可能です?
359             *
360             * @og.rev 4.0.1.0 (2007/12/14) 新規追?
361             *
362             * @param       file    検索??ファイルオブジェク?
363             *
364             * @return      検索??ファイルの??化情報(ただし?見つからなければ、null)
365             */
366            private String findKeywordAsBulk( final File file ) {
367    
368                    boolean isFind = false;
369    
370                    FileString sf = new FileString();
371                    sf.setFilename( file.getPath() );
372                    sf.setEncode( inEncode );
373                    String line = sf.getValue();
374    
375                    Matcher mach = pattern.matcher( line );
376                    if( mach.find() ) {
377                            if( debug ) { println( "DEBUG:\t" + file.getPath() ); }
378                            isFind = true;
379                    }
380    
381                    return ( isFind ) ? line : null;
382            }
383    
384            /**
385             * キーワードを????に置き換えます?
386             * useBackup 属?に true を指定した?合?置き換え後?、backup ファイルは?
387             * オリジナル_backup と?名称に変わります?
388             * ここでは?行づつ読み取りながら、変換処?行います?
389             * よって、?行にまたが?keyword でのマッチングは出来ませんが?大きな
390             * ファイル等での置換でも?メモリの使用量?抑えられます?
391             *
392             * @og.rev 4.0.1.0 (2007/12/14) 置換??独立させます?
393             *
394             * @param       inFile  検索??入力ファイルオブジェク?
395             * @param       outFile 変換後?出力ファイルオブジェク?
396             * @param       firstLineNo     キーワードが存在した場合???の行番号
397             */
398            private void changeKeyword( final File inFile,final File outFile,final int firstLineNo ) {
399    
400                    BufferedReader reader = FileUtil.getBufferedReader( inFile,inEncode );
401                    PrintWriter    writer = FileUtil.getPrintWriter( outFile,outEncode );
402    
403                    String line = null;
404                    try {
405                            int lineNo = 0;
406                            while((line = reader.readLine()) != null) {
407                                    lineNo++ ;
408                                    if( lineNo >= firstLineNo ) {
409                                            Matcher mach = pattern.matcher( line );
410    
411                                            String chnStr = null;
412                                            if( "CHANGE".equals( insert ) ) {
413                                                    chnStr = strChange( mach );
414                                            }
415                                            else if( "BEFORE".equals( insert ) ) {
416                                                    chnStr = strBefore( line,mach );
417                                            }
418                                            else if( "AFTER".equals( insert ) ) {
419                                                    chnStr = strAfter( line,mach );
420                                            }
421    
422                                            if( chnStr != null ) {
423                                                    line = chnStr;
424                                                    cngCount++ ;    // 変換されれ? カウン?
425                                            }
426                                    }
427                                    writer.println( line ); // readLine() してる?で、最後に改行が??
428                            }
429                    }
430                    catch ( IOException ex ) {
431                            String errMsg = "処?にエラーが発生しました?" + line + "]" ;
432                            throw new RuntimeException( errMsg,ex );
433                    }
434                    finally {
435                            Closer.ioClose( reader );
436                            Closer.ioClose( writer );
437                    }
438            }
439            /**
440             * キーワードを????に置き換えます?
441             * useBackup 属?に true を指定した?合?置き換え後?、backup ファイルは?
442             * オリジナル_backup と?名称に変わります?
443             * ここでは、ファイルをすべて読み取ってから、チェ?します?
444             * よって、?行にまたが?keyword でのマッチングが可能です?
445             *
446             * @og.rev 4.0.1.0 (2007/12/14) 置換??独立させます?
447             *
448             * @param       fileLine        検索??行文字?
449             * @param       outFile 出力ファイルオブジェク?
450             */
451            private void changeKeywordAsBulk( final String fileLine,final File outFile ) {
452                    PrintWriter writer = FileUtil.getPrintWriter( outFile,outEncode );
453    
454                    String line = fileLine ;
455                    try {
456                            Matcher mach = pattern.matcher( line );
457    
458                            String chnStr = null;
459                            if( "CHANGE".equals( insert ) ) {
460                                    chnStr = strChange( mach );
461                            }
462                            else if( "BEFORE".equals( insert ) ) {
463                                    chnStr = strBefore( line,mach );
464                            }
465                            else if( "AFTER".equals( insert ) ) {
466                                    chnStr = strAfter( line,mach );
467                            }
468    
469                            if( chnStr != null ) {
470                                    line = chnStr;
471                                    cngCount++ ;    // 変換されれ? カウン?
472                            }
473    
474                            writer.print( line );   // 注意:改行コード?、不?
475                    }
476                    catch ( RuntimeException ex ) {
477                            String errMsg = "処?にエラーが発生しました?" + outFile.getPath() + "]" ;
478                            throw new RuntimeException( errMsg,ex );
479                    }
480                    finally {
481                            Closer.ioClose( writer );
482                    }
483            }
484    
485            /**
486             * insert が?"CHANGE" の場合?処?果を求めます?
487             * 変換しなかった?合?、null を返します?
488             * これは、変換カウントを算?する為のフラグ代わりに使用して?す?
489             *
490             * @param       mach    キーワード?正規表現
491             *
492             * @return      変換結果(対象行で無??合?、null)
493             */
494            private String strChange( final Matcher mach ) {
495                    String line = null;
496                    if( mach.find() ) {
497                            line = mach.replaceAll( change );
498                    }
499                    return line ;
500            }
501    
502            /**
503             * insert が?"BEFORE" の場合?処?果を求めます?
504             * 変換しなかった?合?、null を返します?
505             * これは、変換カウントを算?する為のフラグ代わりに使用して?す?
506             *
507             * @param       line    検索?
508             * @param       mach    キーワード?正規表現
509             *
510             * @return      変換結果(対象行で無??合?、null)
511             */
512            private String strBefore( final String line , final Matcher mach ) {
513                    boolean isChng = false;
514                    StringBuilder buf = new StringBuilder( line.length() );
515                    int indx = 0;
516                    while( mach.find() ) {
517                            isChng = true;
518                            int strt = mach.start() + insOffset;
519                            buf.append( line.substring( indx,strt ) );
520                            buf.append( change );
521                            indx = strt;
522                    }
523    
524                    String rtn = null;
525                    if( isChng ) {
526                            buf.append( line.substring( indx ) );
527                            rtn = buf.toString();
528                    }
529    
530                    return rtn ;
531            }
532    
533            /**
534             * insert が?"AFTER" の場合?処?果を求めます?
535             * 変換しなかった?合?、null を返します?
536             * これは、変換カウントを算?する為のフラグ代わりに使用して?す?
537             *
538             * @param       line    検索?
539             * @param       mach    キーワード?正規表現
540             *
541             * @return      変換結果(対象行で無??合?、null)
542             */
543            private String strAfter( final String line , final Matcher mach ) {
544                    boolean isChng = false;
545                    StringBuilder buf = new StringBuilder( line.length() );
546                    int indx = 0;
547                    while( mach.find() ) {
548                            isChng = true;
549                            int end = mach.end() + insOffset;
550                            buf.append( line.substring( indx,end ) );
551                            buf.append( change );
552                            indx = end;
553                    }
554                    String rtn = null;
555                    if( isChng ) {
556                            buf.append( line.substring( indx ) );
557                            rtn = buf.toString();
558                    }
559    
560                    return rtn ;
561            }
562    
563            /**
564             * プロセスの処?果のレポ?ト表現を返します?
565             * 処??ログラ?、?力件数、?力件数などの??です?
566             * こ???をそのまま、標準?力に出すことで、結果レポ?トと出来るよ?
567             * 形式で出してください?
568             *
569             * @return   処?果のレポ??
570             */
571            public String report() {
572                    if( findCount < cngCount ) { findCount = cngCount; }
573    
574                    String report = "[" + getClass().getName() + "]" + CR
575                                    + TAB + "Search Keyword    : " + keyword    + CR
576                                    + TAB + "Search File Count : " + inCount    + CR
577                                    + TAB + "Key Find    Count : " + findCount  + CR
578                                    + TAB + "Key Change  Count : " + cngCount ;
579    
580                    return report ;
581            }
582    
583            /**
584             * こ?クラスの使用方法を返します?
585             *
586             * @return      こ?クラスの使用方?
587             */
588            public String usage() {
589                    StringBuilder buf = new StringBuilder();
590    
591                    buf.append( "Process_Grep は、上流から受け取っ?FileLineModelから、文字?を見つけ??           ).append( CR );
592                    buf.append( "ChainProcess インターフェースの実?ラスです?"                                                              ).append( CR );
593                    buf.append( CR );
594                    buf.append( "正規表現の keyword を上流から受け取っ?FileLineModel から検索します?"           ).append( CR );
595                    buf.append( "見つかった対象ファイルから、指定???を置換する?合??change ?                  ).append( CR );
596                    buf.append( "-changeFile で、keyword を置換する文字?を指定して下さ??"                                        ).append( CR );
597                    buf.append( "置換する文字?には、\t と \n の特殊文字が使用できます?"                                           ).append( CR );
598                    buf.append( CR );
599                    buf.append( "処?象は??常は?行づつ読み取りながら処?行います?存在チェ?の場合??      ).append( CR );
600                    buf.append( "見つかった時点で処?中止します?これは、該当?をピ?ア??するのではなく?"       ).append( CR );
601                    buf.append( "存在して?かど?を判断して、あれ?、下流に流すと?のが目?からです?"              ).append( CR );
602                    buf.append( "keyword を?改行を含?規表現で、検索・置換する?合??useBulkRead 属??               ).append( CR );
603                    buf.append( "true に設定してください。これ?、?力ファイルを?して読み込みます?"                       ).append( CR );
604                    buf.append( "-ignoreCase は、検索時にキーの大?小文字を無視するよ??します?"            ).append( CR );
605                    buf.append( "-notEquals は、結果(見つかればtrue)を反転(見つからなければtrue)します?"            ).append( CR );
606                    buf.append( "これは、行単位ではなく?ファイル単位に判定します?で、change ?した??             ).append( CR );
607                    buf.append( "でも?対象行?、見つかった行です?ただし?下流に対して、見つからな?                   ).append( CR );
608                    buf.append( "場合だけ??継続させます?"                                                                                                    ).append( CR );
609                    buf.append( "-inEncode は、?力ファイルのエンコード指定になります?"                                          ).append( CR );
610                    buf.append( "-outEncode は、?力ファイルのエンコードや、changeFileで??置換文字?"          ).append( CR );
611                    buf.append( "ファイルのエンコード指定になります?(changeFile は、? 出力ファイルと)"                 ).append( CR );
612                    buf.append( "同じエンコードです?"                                                                                                                 ).append( CR );
613                    buf.append( "これら?エンコードが無??場合?、System.getProperty(\"file.encoding\") "      ).append( CR );
614                    buf.append( "で求まる?を使用します?"                                                                                                              ).append( CR );
615                    buf.append( "-changeFile を使用することで、?行???に置換することが可能です?"             ).append( CR );
616                    buf.append( CR );
617                    buf.append( "上?プロセスチェインの??タは上流から渡されます?)からのLineModel の"            ).append( CR );
618                    buf.append( "ファイルオブジェクトより?????が含まれて?か検索します?"                   ).append( CR );
619                    buf.append( "上流?ロセスでは、Name 属?として、?File』を持ち、?は、Fileオブジェク?            ).append( CR );
620                    buf.append( "である、Process_FileSearch を使用するのが?便利です?それ以外?クラス?           ).append( CR );
621                    buf.append( "使用する場合でも?Name属?と、File オブジェクトを持つ LineModel を受け渡?  ).append( CR );
622                    buf.append( "できれば、使用可能です?"                                                                                                            ).append( CR );
623                    buf.append( CR );
624                    buf.append( "引数??中に空白を含??合?、ダブルコー??ション(\"\") で括って下さ??" ).append( CR );
625                    buf.append( "引数??の ?』?前後には、空白は挟めません。??key=value の様に"             ).append( CR );
626                    buf.append( "繋げてください?                                                                                                                              ).append( CR );
627                    buf.append( CR ).append( CR );
628    
629                    buf.append( getArgument().usage() ).append( CR );
630    
631                    return buf.toString();
632            }
633    
634            /**
635             * こ?クラスは、main メソ?から実行できません?
636             *
637             * @param       args    コマンド引数配?
638             */
639            public static void main( final String[] args ) {
640                    LogWriter.log( new Process_Grep().usage() );
641            }
642    }