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 */ 016package org.opengion.fukurou.process; 017 018import org.opengion.fukurou.system.OgRuntimeException; // 6.4.2.0 (2016/01/29) 019import org.opengion.fukurou.system.OgCharacterException; // 6.5.0.1 (2016/10/21) 020import org.opengion.fukurou.system.Closer; 021import org.opengion.fukurou.system.LogWriter; 022import org.opengion.fukurou.util.Argument; 023import org.opengion.fukurou.util.FileUtil; 024import org.opengion.fukurou.util.StringUtil; 025import org.opengion.fukurou.util.CommentLineParser; // 6.3.1.1 (2015/07/10) 026import org.opengion.fukurou.util.FileInfo; // 6.4.0.2 (2015/12/11) 027import org.opengion.hayabusa.common.HybsSystem; // 8.1.3.0 (2022/06/03) 028 029import java.util.Arrays; 030import java.util.Enumeration; // 8.1.3.0 (2022/06/03) 031import java.util.jar.JarFile; // 8.1.3.0 (2022/06/03) 032import java.util.jar.JarEntry; // 8.1.3.0 (2022/06/03) 033import java.util.LinkedHashMap; 034import java.util.Locale; // 8.1.3.0 (2022/06/03) 035import java.util.Map; 036import java.util.regex.Pattern; 037import java.util.regex.Matcher; 038 039import java.io.File; 040import java.io.PrintWriter; 041import java.io.BufferedReader; 042import java.io.IOException; 043import java.io.InputStreamReader; // 8.1.3.0 (2022/06/03) 044import java.io.InputStream; // 8.1.3.0 (2022/06/03) 045import java.nio.charset.CharacterCodingException; // 6.3.1.0 (2015/06/28) 046 047/** 048 * Process_Grep は、上流から受け取った FileLineModelから、文字列を見つけ出す 049 * ChainProcess インターフェースの実装クラスです。 050 * 051 * 正規表現の keyword を上流から受け取った FileLineModel から検索します。 052 * 見つかった対象ファイルから、指定の文字列を置換する場合は、-change か 053 * -changeFile で、keyword を置換する文字列を指定して下さい。 054 * 置換する文字列には、\t と \n の特殊文字が使用できます。 055 * 056 * 処理対象は、通常は、1行づつ読み取りながら処理を行います。存在チェックの場合は、 057 * 見つかった時点で処理を中止します。これは、該当箇所をピックアップするのではなく、 058 * 存在しているかどうかを判断して、あれば、下流に流すというのが目的だからです。 059 * keyword を、改行を含む正規表現で、検索・置換する場合は、-useBulkRead 属性を 060 * true に設定してください。これは、入力ファイルを一括して読み込みます。 061 * -ignoreCase は、検索時にキーの大文字小文字を無視するように指定します。 062 * -notEquals は、結果(見つかればtrue)を反転(見つからなければtrue)します。 063 * これは、行単位ではなく、ファイル単位に判定しますので、change 指定した場合 064 * でも、対象行は、見つかった行です。ただし、下流に対して、見つからない 065 * 場合だけ処理を継続させます。 066 * -inEncode は、入力ファイルのエンコード指定になります。 067 * -outEncode は、出力ファイルのエンコードや、changeFileで指定の置換文字列ファイルの 068 * エンコード指定になります。(changeFile は、必ず 出力ファイルと同じエンコードです。) 069 * これらのエンコードが無指定の場合は、System.getProperty("file.encoding") で 070 * 求まる値を使用します。 071 * -changeFile を使用することで、複数行の文字列に置換することが可能です。 072 * -outfile では、処理を行ったファイル名一覧をセーブします。 073 * 074 * 上流(プロセスチェインのデータは上流から渡されます。)からのLineModel の 075 * ファイルオブジェクトより、指定の文字列が含まれているか検索します。 076 * 上流プロセスでは、Name 属性として、『File』を持ち、値は、Fileオブジェクト 077 * である、Process_FileSearch を使用するのが、便利です。それ以外のクラスを 078 * 使用する場合でも、Name属性と、File オブジェクトを持つ LineModel を受け渡し 079 * できれば、使用可能です。 080 * 081 * ※ 6.3.1.1 (2015/07/10) useOmitCmnt、useAllFind 機能追加 082 * 083 * 引数文字列中に空白を含む場合は、ダブルコーテーション("") で括って下さい。 084 * 引数文字列の 『=』の前後には、空白は挟めません。必ず、-key=value の様に 085 * 繋げてください。 086 * 087 * ※ 8.1.3.0 (2022/06/03) jarPrefix、jarSuffix、jarInstr、useRegexp、saveFile 追加 088 * jar ファイルの中身も検索します。その際、jarファイルに圧縮されているファイル名での 089 * 絞り込みができるように、指定できる属性を追加します。 090 * ただし、jarファイル内の検索は、useAllFind=true(置換ではなく検索だけ最後まで行う)のみです。 091 * 上流から jar ファイルが指定された場合は、常に検索対象になります。 092 * 093 * @og.formSample 094 * Process_Grep -keyword=検索文字列 -ignoreCase=true -outfile=OUTFILE -encode=UTF-8 095 * 096 * -keyword=キーワード :検索する語句 097 * [-ignoreCase=大文字小文字 ] :検索時に大文字小文字を区別しない(true)かどうか(初期値:区別する[false]) 098 * [-notEquals=判定結果の反転] :判定結果を反転させる(true)かどうか(初期値:反転させない[false]) 099 * [-inEncode=入力エンコード ] :入力ファイルのエンコードタイプ 100 * [-outEncode=出力エンコード ] :出力ファイルや置換ファイルのエンコードタイプ 101 * [-change=置換文字列 ] :-change="ABCD" \t や \n などの特殊文字が使用できます。 102 * [-changeFile=置換ファイル ] :-changeFile=change.txt このファイルの記述すべてと置換します。 103 * -change と、-changeFile は、同時に指定できません。 104 * 置換機能使用時は、必ず、_backup というファイルが作成されます。 105 * [-insert=[HEAD/CHANGE/BEFORE/AFTER/TAIL] ] 106 * : 置換でなく挿入する場合の位置を指定します(初期値:CHANGE) 107 * スペースで区切って数字を記述すると、挿入位置にオフセットできます。 108 * [-delete=[false/true] ] : 置換でなく削除します(初期値:false) 109 * [-skipRowCount=スキップ行数 ] : 先頭行から、スキップする行数を指定します(useBulkRead時には使用されません) 110 * [-useBackup=[false/true] ] :trueは、backupファイルを作成します(初期値:false) 111 * [-useBulkRead=[false/true]] :trueは、入力ファイルを一括読込します(初期値:false) 112 * [-useAllFind=[false/true] ] :置換ではなく検索だけ最後まで行う場合、trueを指定します(初期値:false) 113 * [-useOmitCmnt=[false/true]] :コメント部分を削除したファイルでgrep処理を行うかどうかを指定(初期値:false) 114 * [-errAbend=[true/false] ] :異常発生時に、処理を中断(true)するか、継続(false)するかを指定する(初期値:true[中断する]) 115 * [-jarPrefix=接頭辞 ] :File・・・・,View・・・・,など、指定の接頭辞で始まるjarファイルを中を検索 8.1.3.0 (2022/06/03) 116 * [-jarSuffix=接尾辞 ] :.txt|.java|.jsp.... など、指定の接尾辞で終わるjarファイルを中を検索 8.1.3.0 (2022/06/03) 117 * [-jarInstr=部分文字列 ] :jarファイルを中と一致する部分文字列を指定 8.1.3.0 (2022/06/03) 118 * [-useRegexp=[false/true] ] :trueは、正規表現で検索します(初期値:false) 8.1.3.0 (2022/06/03) 119 * [-saveFile=保存ファイル ] :検索結果を指定ファイルに保存します 8.1.3.0 (2022/06/03) 120 * [-display=[false/true] ] :trueは、検索状況を表示します(初期値:false) 121 * [-debug=[false/true] ] :デバッグ情報を標準出力に表示する(true)かしない(false)か(初期値:false[表示しない]) 122 * 123 * @version 4.0 124 * @author Kazuhiko Hasegawa 125 * @since JDK5.0, 126 */ 127public class Process_Grep extends AbstractProcess implements ChainProcess { 128 private static final String[] INSERT_LIST = { "HEAD","CHANGE","BEFORE","AFTER","TAIL" }; // 6.2.4.0 (2015/05/15) 129 private static final String ENCODE = "UTF-8"; // 8.1.3.0 (2022/06/03) 130 private static final String AUTO_ENCODE = "autoEncode"; // 8.1.3.0 (2022/06/03) 131 132 /** 8.1.3.0 (2022/06/03) 拡張子をエンコードに変換するMap */ 133 private static final Map<String,String> EXT2ENC = Map.ofEntries( 134 Map.entry("bat" , "Windows-31J"), Map.entry("ken" , "Windows-31J"), 135 Map.entry("sql" , "Windows-31J"), Map.entry("vbs" , "Windows-31J"), 136 Map.entry("css" , "UTF-8"), Map.entry("html" , "UTF-8"), 137 Map.entry("java" , "UTF-8"), Map.entry("js" , "UTF-8"), 138 Map.entry("jsp" , "UTF-8"), Map.entry("xml" , "UTF-8"), 139 Map.entry("jar" , "UTF-8") // 除外されない為に追記 140 ); 141 142 private Pattern pattern; 143 private String keyword; 144 private boolean ignoreCase; 145 private boolean notEquals; 146 private String inEncode; 147 private String outEncode; 148 private String change; 149 private String insert = "CHANGE"; // "HEAD","CHANGE","BEFORE","AFTER","TAIL" のどれか 150 private int insOffset; // "BEFORE","AFTER" 時のオフセット 151 private boolean useBackup; 152 private boolean useBulkRead; // 4.0.1.0 (2007/12/14) 一括読込 153 private boolean delete; 154 private boolean useAllFind; // 6.3.1.1 (2015/07/10) 最後まで検索 155 private boolean useOmitCmnt; // 6.3.1.1 (2015/07/10) コメント除外 156 private boolean errAbend = true; // 6.3.1.0 (2015/06/28) 中断する 157 private String jarPrefix; // 8.1.3.0 (2022/06/03) 158 private String jarSuffix; // 8.1.3.0 (2022/06/03) 159 private String jarInstr; // 8.1.3.0 (2022/06/03) 160 private boolean useRegexp; // 8.1.3.0 (2022/06/03) 161 private String saveFile; // 8.1.3.0 (2022/06/03) 162 private boolean display; 163 private boolean debug; // 5.1.2.0 (2010/01/01) 164 165 private int inCount; 166 private int findCount; 167 private int cngCount; 168 private int skipRowCount; // 6.2.4.0 (2015/05/15) 行スキップ 169 private PrintWriter outWriter; // 8.1.3.0 (2022/06/03) PrintWriterオブジェクト 170 private final String fileURL = HybsSystem.sys( "FILE_URL" ); // 8.1.3.0 (2022/06/03) ファイルURL 171 172 /** staticイニシャライザ後、読み取り専用にするので、ConcurrentHashMap を使用しません。 */ 173 private static final Map<String,String> MUST_PROPARTY ; // [プロパティ]必須チェック用 Map 174 /** staticイニシャライザ後、読み取り専用にするので、ConcurrentHashMap を使用しません。 */ 175 private static final Map<String,String> USABLE_PROPARTY ; // [プロパティ]整合性チェック Map 176 177 static { 178 MUST_PROPARTY = new LinkedHashMap<>(); 179 MUST_PROPARTY.put( "keyword", "検索する語句(必須)" ); 180 181 USABLE_PROPARTY = new LinkedHashMap<>(); 182 USABLE_PROPARTY.put( "ignoreCase", "検索時に大文字小文字を区別しない(true)かどうか。" + 183 CR + "(初期値:区別する[false])" ); 184 USABLE_PROPARTY.put( "notEquals", "検索時に判定結果を反転させる(true)かどうか。" + 185 CR + "(初期値:反転させない[false])" ); 186 USABLE_PROPARTY.put( "inEncode", "入力ファイルのエンコードタイプ" ); 187 USABLE_PROPARTY.put( "outEncode", "出力ファイルや置換ファイルのエンコードタイプ" ); 188 USABLE_PROPARTY.put( "change", "置換文字列 例: -change=\"ABCD\" \\t や \\n などの特殊文字が使用できます。" ); 189 USABLE_PROPARTY.put( "changeFile", "置換文字列ファイル 例: -changeFile=change.txt" + 190 CR + "-change と、-changeFile は、同時に指定できません。" + 191 CR + "置換機能使用時は、必ず、_backup というファイルが作成されます。" ); 192 USABLE_PROPARTY.put( "insert", "[HEAD/CHANGE/BEFORE/AFTER/TAIL]:置換でなく挿入する場合の位置を指定します(初期値:CHANGE)" + 193 CR + "スペースで区切って数字を記述すると、挿入位置にオフセットできます。" ); 194 USABLE_PROPARTY.put( "delete", "[false/true]:trueは、置換でなく削除します(初期値:false)" ); 195 USABLE_PROPARTY.put( "skipRowCount","先頭行から、スキップする行数を指定します。" ); // 6.2.4.0 (2015/05/15) 196 USABLE_PROPARTY.put( "useBackup", "[false/true]:trueは、backupファイルを作成します(初期値:false)" ); 197 USABLE_PROPARTY.put( "useBulkRead", "[false/true]:trueは、入力ファイルを一括読込します(初期値:false)" ); 198 USABLE_PROPARTY.put( "useAllFind", "置換ではなく検索だけ最後まで行う場合、trueを指定します(初期値:false)" ); // 6.3.1.1 (2015/07/10) 199 USABLE_PROPARTY.put( "useOmitCmnt", "コメント部分を削除したファイルでgrep処理を行うかどうかを指定(初期値:false)" ); // 6.3.1.1 (2015/07/10) 200 USABLE_PROPARTY.put( "jarPrefix", "File・・・・,View・・・・,など、指定の接頭辞で始まるjarファイルを中を検索" ); // 8.1.3.0 (2022/06/03) 201 USABLE_PROPARTY.put( "jarSuffix", ".txt|.java|.jsp.... など、指定の接尾辞で終わるjarファイルを中を検索" ); // 8.1.3.0 (2022/06/03) 202 USABLE_PROPARTY.put( "jarInstr", "jarファイルを中と一致する部分文字列を指定" ); // 8.1.3.0 (2022/06/03) 203 USABLE_PROPARTY.put( "useRegexp", "[false/true]:trueは、正規表現で検索します(初期値:false)" ); // 8.1.3.0 (2022/06/03) 204 USABLE_PROPARTY.put( "errAbend", "異常発生時に、処理を中断(true)するか、継続(false)するか" + 205 CR + "(初期値:true:中断する)" ); // 6.3.1.0 (2015/06/28) 206 USABLE_PROPARTY.put( "saveFile", "検索結果を指定ファイルに保存します" ); // 8.1.3.0 (2022/06/03) 207 USABLE_PROPARTY.put( "display", "[false/true]:trueは、検索状況を表示します(初期値:false)" ); 208 USABLE_PROPARTY.put( "debug", "デバッグ情報を標準出力に表示する(true)かしない(false)か" + 209 CR + "(初期値:false:表示しない)" ); 210 } 211 212 /** 213 * デフォルトコンストラクター。 214 * このクラスは、動的作成されます。デフォルトコンストラクターで、 215 * super クラスに対して、必要な初期化を行っておきます。 216 * 217 */ 218 public Process_Grep() { 219 super( "org.opengion.fukurou.process.Process_Grep",MUST_PROPARTY,USABLE_PROPARTY ); 220 } 221 222 /** 223 * プロセスの初期化を行います。初めに一度だけ、呼び出されます。 224 * 初期処理(ファイルオープン、DBオープン等)に使用します。 225 * 226 * @og.rev 6.3.1.0 (2015/06/28) errAbend属性追加。 227 * @og.rev 6.3.1.1 (2015/07/10) useOmitCmnt、useAllFind 機能追加 228 * @og.rev 8.1.3.0 (2022/06/03) jarファイル内の検索、オートエンコード対応 229 * 230 * @param paramProcess データベースの接続先情報などを持っているオブジェクト 231 */ 232 public void init( final ParamProcess paramProcess ) { 233 final Argument arg = getArgument(); 234 235 keyword = arg.getProparty( "keyword"); 236 ignoreCase = arg.getProparty( "ignoreCase" ,ignoreCase ); 237 notEquals = arg.getProparty( "notEquals" ,notEquals ); 238 inEncode = arg.getProparty( "inEncode" ,System.getProperty("file.encoding")); 239 outEncode = arg.getProparty( "outEncode" ,System.getProperty("file.encoding")); 240 useBackup = arg.getProparty( "useBackup" ,useBackup ); 241 useBulkRead = arg.getProparty( "useBulkRead",useBulkRead); // 4.0.1.0 (2007/12/14) 242 delete = arg.getProparty( "delete" ,delete ); 243 insert = arg.getProparty( "insert" ,insert ); 244 change = arg.getFileProparty( "change" ,"changeFile",outEncode,false ); 245 skipRowCount = arg.getProparty( "skipRowCount",0 ); // 6.2.4.0 (2015/05/15) 246 useAllFind = arg.getProparty( "useAllFind" ,useAllFind); // 6.3.1.1 (2015/07/10) 247 useOmitCmnt = arg.getProparty( "useOmitCmnt",useOmitCmnt); // 6.3.1.1 (2015/07/10) 248 errAbend = arg.getProparty( "errAbend" ,errAbend ); // 6.3.1.0 (2015/06/28) errAbend属性追加 249 jarPrefix = arg.getProparty( "jarPrefix" ,jarPrefix ); // 8.1.3.0 (2022/06/03) 250 jarSuffix = arg.getProparty( "jarSuffix" ,jarSuffix ); // 8.1.3.0 (2022/06/03) 251 jarInstr = arg.getProparty( "jarInstr" ,jarInstr ); // 8.1.3.0 (2022/06/03) 252 useRegexp = arg.getProparty( "useRegexp" ,useRegexp ); // 8.1.3.0 (2022/06/03) 253 saveFile = arg.getProparty( "saveFile" ,saveFile ); // 8.1.3.0 (2022/06/03) 254 display = arg.getProparty( "display" ,display ); 255 debug = arg.getProparty( "debug" ,debug ); // 5.1.2.0 (2010/01/01) 256 257 if( change != null ) { 258 final int adrs = insert.indexOf( ' ' ); // オフセット数字の有無 259 if( adrs > 0 ) { 260 insOffset = Integer.parseInt( insert.substring( adrs+1 ) ); 261 insert = insert.substring( 0,adrs ); 262 } 263 264 boolean isOK = false; 265 for( int i=0; i<INSERT_LIST.length; i++ ) { 266 if( insert.equalsIgnoreCase( INSERT_LIST[i] ) ) { 267 isOK = true; break; 268 } 269 } 270 if( !isOK ) { 271 // 実行時エラーではないので、errAbend 対象外 272 final String errMsg = "insert は、" + Arrays.toString( INSERT_LIST ) 273 + " から指定してください。" + CR 274 + "-insert=[" + insert + "]" ; 275 throw new OgRuntimeException( errMsg ); 276 } 277 278 change = StringUtil.replace( change,"\\n",CR ); 279 change = StringUtil.replace( change,"\\t","\t" ); 280 } 281 282 if( delete ) { change = ""; } // 削除は、"" 文字列と置換します。 283 284 // 8.1.3.0 (2022/06/03) Modify 285// if( ignoreCase ) { 286// pattern = Pattern.compile( keyword,Pattern.CASE_INSENSITIVE ); 287// } 288// else { 289// pattern = Pattern.compile( keyword ); 290// } 291 // 大文字小文字を区別しない 292 if( ignoreCase ) { 293 if( useRegexp ) { pattern = Pattern.compile( keyword,Pattern.CASE_INSENSITIVE ); } // 正規表現を使用する 294 else { keyword = keyword.toLowerCase( Locale.JAPAN ); } 295 } 296 // 大文字小文字を区別する 297 else { 298 if( useRegexp ) { pattern = Pattern.compile( keyword ); } // 正規表現を使用しない 299 } 300 301 // jarファイルの接頭辞/接尾辞/部分文字列 302 if( StringUtil.isNotNull(jarPrefix) ){ jarPrefix = jarPrefix.toLowerCase( Locale.JAPAN ); } 303 if( StringUtil.isNotNull(jarSuffix) ){ jarSuffix = jarSuffix.toLowerCase( Locale.JAPAN ); } 304 if( StringUtil.isNotNull(jarInstr) ){ jarInstr = jarInstr.toLowerCase( Locale.JAPAN ); } 305 306 // 8.1.3.0 (2022/06/03) 保存ファイル指定有り 307 if( StringUtil.isNotNull(saveFile) ){ 308 final String filename = HybsSystem.url2dir( StringUtil.urlAppend( fileURL, saveFile ) ); 309 outWriter = FileUtil.getPrintWriter( new File( filename ), ENCODE, true ); 310 } 311 } 312 313 /** 314 * プロセスの終了を行います。最後に一度だけ、呼び出されます。 315 * 終了処理(ファイルクローズ、DBクローズ等)に使用します。 316 * 317 * @og.rev 8.1.3.0 (2022/06/03) jarファイル内の検索、オートエンコード対応 318 * 319 * @param isOK トータルで、OKだったかどうか[true:成功/false:失敗] 320 */ 321 public void end( final boolean isOK ) { 322 // 8.1.3.0 (2022/06/03) 保存ファイル指定有り 323 if( StringUtil.isNotNull(saveFile) ){ 324 Closer.ioClose( outWriter ); 325 } 326 } 327 328 /** 329 * 引数の LineModel を処理するメソッドです。 330 * 変換処理後の LineModel を返します。 331 * 後続処理を行わない場合(データのフィルタリングを行う場合)は、 332 * null データを返します。つまり、null データは、後続処理を行わない 333 * フラグの代わりにも使用しています。 334 * なお、変換処理後の LineModel と、オリジナルの LineModel が、 335 * 同一か、コピー(クローン)かは、各処理メソッド内で決めています。 336 * ドキュメントに明記されていない場合は、副作用が問題になる場合は、 337 * 各処理ごとに自分でコピー(クローン)して下さい。 338 * 339 * @og.rev 4.0.1.0 (2007/12/14) ファイルの一括処理対応。 340 * @og.rev 5.7.2.2 (2014/01/24) エラー時にデータも出力します。 341 * @og.rev 6.3.1.0 (2015/06/28) errAbend属性追加。 342 * @og.rev 8.1.3.0 (2022/06/03) jarファイル内の検索、オートエンコード対応 343 * 344 * @param data オリジナルのLineModel 345 * 346 * @return 処理変換後のLineModel 347 */ 348 @Override // ChainProcess 349 public LineModel action( final LineModel data ) { 350 inCount++ ; 351 352 final FileLineModel fileData ; 353 if( data instanceof FileLineModel ) { 354 fileData = (FileLineModel)data ; 355 } 356 else { 357 // これは、プログラマーの問題なので、errAbend 対象外 358 final String errMsg = "データが FileLineModel オブジェクトではありません。" + CR ; 359 throw new OgRuntimeException( errMsg ); 360 } 361 362 final File file = fileData.getFile() ; 363 if( !file.isFile() ) { 364 if( display ) { println( data.dataLine() ); } // 5.1.2.0 (2010/01/01) display の条件変更 365 return data; 366 } 367 368 boolean isFind = false ; // 6.3.1.0 (2015/06/28) errAbend属性追加に伴う、初期化漏れ対応 369 try { 370 String fileLine = null; 371 int firstLineNo = -1; 372 373 // 8.1.3.0 (2022/06/03) 拡張子によるエンコード指定 374 final String mapEnc = getEncode( file ); 375 // 8.1.3.0 (2022/06/03) 該当するエンコード無し 376 if( !"-".equals(mapEnc) ) { 377 // 8.1.3.0 (2022/06/03) jarファイル内の検索 378// if( useBulkRead ) { fileLine = findKeywordAsBulk( file ); } 379// else { firstLineNo = findKeyword( file ); } 380 if( useBulkRead ) { fileLine = findKeywordAsBulk( file,mapEnc ); } 381 else { 382 if( file.getName().endsWith( ".jar" ) ) { findJarKeyword( file ); } // firstLineNo は、常に -1 383 else { firstLineNo = findKeyword( file,mapEnc ); } 384 } 385 } 386 387 isFind = fileLine != null || firstLineNo >= 0 ; 388 389 // 置換処理 ただし、見つかったときのみ実行 390 if( change != null && isFind ) { 391 // 入力ファイルは、オリジナル_backup ファイルとする。過去のファイルを削除 392 final File inFile = new File( file.getPath() + "_backup" ); 393 if( inFile.exists() && !inFile.delete() ) { 394 final String errMsg = "過去のBKUPファイルを削除できませんでした。[" + inFile + "]" + CR 395 + "data=[" + data.dataLine() + "]" + CR ; // 5.7.2.2 (2014/01/24) エラー時にデータも出力します。 396 // try の中から throw するのは、行儀がよくないが、catch ブロックで errAbend処理する。 397 throw new OgRuntimeException( errMsg ); 398 } 399 400 // オリジナルのファイルを、_backup ファイル名に先に変換する。 401 final File fromFile = new File( file.getPath() ); 402 if( !fromFile.renameTo( inFile ) ) { 403 final String errMsg = "所定のファイルをリネームできませんでした。[" + fromFile + "]" + CR 404 + "data=[" + data.dataLine() + "]" + CR ; // 5.7.2.2 (2014/01/24) エラー時にデータも出力します。 405 // try の中から throw するのは、行儀がよくないが、catch ブロックで errAbend処理する。 406 throw new OgRuntimeException( errMsg ); 407 } 408 409 // 変換処理 本体 410 if( useBulkRead ) { changeKeywordAsBulk( fileLine,file ); } 411// else { changeKeyword( inFile,file,firstLineNo ); } 412 else { changeKeyword( inFile,file,firstLineNo,mapEnc ); } // 8.1.3.0 (2022/06/03) 413 414 // backup を使わない場合は、削除する。 415 // 4.0.0.0 (2007/11/29) 入れ子if の統合 416 if( !useBackup && !inFile.delete() ) { 417 final String errMsg = "所定のファイルを削除できませんでした。[" + inFile + "]" + CR 418 + "data=[" + data.dataLine() + "]" + CR ; // 5.7.2.2 (2014/01/24) エラー時にデータも出力します。 419 // try の中から throw するのは、行儀がよくないが、catch ブロックで errAbend処理する。 420 throw new OgRuntimeException( errMsg ); 421 } 422 } 423 } 424 catch( final RuntimeException ex ) { 425 final String errMsg = "処理中にエラーが発生しました。[" + data.getRowNo() + "]件目" + CR 426 + "data=[" + data.dataLine() + "]" + CR ; // 5.7.2.2 (2014/01/24) エラー時にデータも出力します。 427 // 6.3.1.0 (2015/06/28) errAbend属性追加。 428 throwException( errMsg,ex,errAbend ); 429 } 430 431// if( display && ( notEquals ^ isFind ) ) { println( data.dataLine() ); } // 5.1.2.0 (2010/01/01) display の条件変更 432 if( notEquals ^ isFind && display ) { println( data.dataLine() ); } // 5.1.2.0 (2010/01/01) display の条件変更 // 6.9.7.0 (2018/05/14) PMD Useless parentheses. 433 return notEquals ^ isFind ? data : null ; 434 } 435 436 /** 437 * キーワードが存在しているかどうかをチェックします。 438 * ここでは、1行づつ読み取りながら、すべてのキーワードをピックアップします。 439 * 440 * @og.rev 8.1.3.0 (2022/06/03) jarファイル内の検索、オートエンコード対応 441 * 442 * @param file 検索元のファイルオブジェクト 443 */ 444 private void findJarKeyword( final File file ) { 445 JarFile jarFile = null; 446 447 try { 448 jarFile = new JarFile( file ); 449 450 final Enumeration<JarEntry> flEnum = jarFile.entries() ; // Generics警告対応 451 while( flEnum.hasMoreElements() ) { 452 final JarEntry ent = flEnum.nextElement(); // Generics警告対応 453 if( ent.isDirectory() ) { continue; } 454 455 final String fileName = ent.getName(); // jarファイル内のファイル 456 457 // 拡張子によるエンコード指定 458 final String mapEnc = getEncode( fileName ); 459 // 該当するエンコード無し 460 if( "-".equals(mapEnc) ) { continue; } 461 462 final String lowName = fileName.toLowerCase( Locale.JAPAN ); 463 if( ( jarPrefix == null || lowName.startsWith( jarPrefix ) ) && 464 ( jarSuffix == null || lowName.endsWith( jarSuffix ) ) && 465 ( jarInstr == null || lowName.contains( jarInstr ) ) ) { 466 467 InputStream stream = null; 468 try { 469 stream = jarFile.getInputStream( ent ) ; 470 471 final BufferedReader reader = new BufferedReader( new InputStreamReader( stream, mapEnc ) ); 472 473 final CommentLineParser clp = useOmitCmnt ? new CommentLineParser( FileInfo.getSUFIX( fileName ) ) : null; 474 try { 475 String line ; 476 int lineNo = 0; 477 while((line = reader.readLine()) != null) { 478 lineNo++ ; // 注意:ここで返す行数は、コメント行を含む行数とする 479 480 // useOmitCmnt 機能(コメント行を削除する処理を入れる) 481 if( useOmitCmnt ) { 482 line = clp.line( line ); 483 if( line == null ) { continue; } // 戻り値が null の場合は、行として不成立 484 } 485 486 // キーワードを含むかどうか判定 487 if( isKeyword( line ) ) { 488 final String msg = file.getPath() + "\\" + fileName + '(' + lineNo + "):" + line ; 489 if( debug ) { 490 final String buf = "DEBUG:\t" + msg ; 491 println( buf ); 492 } 493 // useAllFind=true 相当の処理のみ行う 494 println( msg ); 495 // 保存ファイル指定有り 496 if( StringUtil.isNotNull(saveFile) ){ outWriter.println( msg ); } 497 498 // useAllFind 機能(最後まで検索を続ける) 499 if( !useAllFind ) { break; } 500 } 501 } 502 } 503 // nioを使用すると UTF-8とShuft-JISで、エラーになる 504 catch( final CharacterCodingException ex ) { 505 final String errMsg = "文字のエンコード・エラーが発生しました。" + CR 506 + " ファイルのエンコードが指定のエンコードと異なります。" + CR 507 + " [" + file.getPath() + "] , Encode=[" + mapEnc + "]" ; 508 // 呼出元で errAbend 処理するので、そのまま throw しておく 509 throw new OgCharacterException( errMsg,ex ); 510 } 511 catch( final IOException ex ) { 512 final String errMsg = "キーワードファイル読取エラーが発生しました。" + CR 513 + " [" + file.getPath() + "] , Encode=[" + mapEnc + "]" ; 514 // 呼出元で errAbend 処理するので、そのまま throw しておく 515 throw new OgRuntimeException( errMsg,ex ); 516 } 517 finally { 518 Closer.ioClose( reader ); 519 } 520 } 521 finally { 522 Closer.ioClose( stream ); 523 } 524 } 525 } 526 } 527 catch( final IOException ex ) { 528 final String errMsg = "キーワードファイル読取エラーが発生しました。" + CR 529 + " [" + file.getPath() + "] , Encode=[" + inEncode + "]" ; 530 // 呼出元で errAbend 処理するので、そのまま throw しておく 531 throw new OgRuntimeException( errMsg,ex ); 532 } 533 finally { 534 Closer.zipClose( jarFile ); 535 } 536 } 537 538 /** 539 * 拡張子をエンコードに変換します。 540 * 541 * @og.rev 8.1.3.0 (2022/06/03) jarファイル内の検索、オートエンコード対応 542 * 543 * @param file 検索元のファイル 544 * @return エンコード 545 */ 546 private String getEncode( final File file ) { 547 return getEncode( file.getName() ); 548 } 549 550 /** 551 * 拡張子をエンコードに変換します。 552 * 553 * @og.rev 8.1.3.0 (2022/06/03) jarファイル内の検索、オートエンコード対応 554 * 555 * @param fileName 検索元のファイル名 556 * @return エンコード 557 */ 558 private String getEncode( final String fileName ) { 559 // 自動判定 560 if( AUTO_ENCODE.equalsIgnoreCase( inEncode ) ) { 561 final String sufix = FileInfo.getSUFIX( fileName ); // 拡張子取得 562 return StringUtil.nval( EXT2ENC.get( sufix ), "-" ); 563 } 564 else { 565 return StringUtil.nval( inEncode, "-" ); 566 } 567 } 568 569 /** 570 * 該当の行にキーワードを含むかどうか判定します。 571 * 572 * @og.rev 8.1.3.0 (2022/06/03) jarファイル内の検索、オートエンコード対応 573 * 574 * @param line 検索元のファイルの行 575 * @return キーワードを含むかどうか[true/false] 576 */ 577 private boolean isKeyword( final String line ) { 578 // 正規表現を使用する 579 if( useRegexp ){ 580 final Matcher mach = pattern.matcher( line ); 581 return mach.find(); 582 } 583 // 正規表現を使用しない 584 else { 585 // 大文字小文字を区別しない 586 if( ignoreCase ) { 587 return line.toLowerCase( Locale.JAPAN ).contains( keyword ); 588 } 589 // 大文字小文字を区別する 590 else { 591 return line.contains( keyword ); 592 } 593 } 594 } 595 596 /** 597 * キーワードが存在しているかどうかをチェックします。 598 * ここでは、1行づつ読み取りながら、最初に見つかった時点で制御を返します。 599 * よって、複数行にまたがる keyword でのマッチングは出来ませんが、大きな 600 * ファイル等での検索には、効率的です。 601 * 602 * @og.rev 4.0.1.0 (2007/12/14) 新規追加 603 * @og.rev 6.3.1.0 (2015/06/28) nioを使用すると UTF-8とShuft-JISで、エラーになる。 604 * @og.rev 6.3.1.0 (2015/06/28) errAbend属性追加。 605 * @og.rev 6.3.1.1 (2015/07/10) useOmitCmnt、useAllFind 機能追加 606 * @og.rev 6.4.0.2 (2015/12/11) CommentLineParser 改造。 607 * @og.rev 6.5.0.1 (2016/10/21) CharacterCodingException は、OgCharacterException に変換する。 608 * @og.rev 8.1.3.0 (2022/06/03) jarファイル内の検索、オートエンコード対応 609 * 610 * @param file 検索元のファイルオブジェクト 611 * @param mapEnc 検索元のファイルエンコード 612 * 613 * @return 最初に見つかった行番号(見つからなければ、-1 を返す) 614 */ 615// private int findKeyword( final File file ) { 616 private int findKeyword( final File file ,final String mapEnc ) { // 8.1.3.0 (2022/06/03) 617 int firstLineNo = -1; 618// final BufferedReader reader = FileUtil.getBufferedReader( file,inEncode ); 619 final BufferedReader reader = FileUtil.getBufferedReader( file,mapEnc ); // 8.1.3.0 (2022/06/03) 620 621 // 6.4.0.2 (2015/12/11) CommentLineParser 改造 622 final CommentLineParser clp = useOmitCmnt ? new CommentLineParser( FileInfo.getSUFIX( file ) ) : null; 623 try { 624 String line ; 625 int lineNo = 0; 626 while((line = reader.readLine()) != null) { 627 lineNo++ ; // 注意:ここで返す行数は、コメント行を含む行数とする。 628 629 // 6.3.1.1 (2015/07/10) useOmitCmnt 機能。コメント行を削除する処理を入れる。 630 if( useOmitCmnt ) { 631 line = clp.line( line ); 632 if( line == null ) { continue; } // 戻り値が null の場合は、行として不成立 633 } 634 // 8.1.3.0 (2022/06/03) Modify 635// final Matcher mach = pattern.matcher( line ); 636// if( mach.find() ) { 637 // キーワードを含むかどうか判定 638 if( isKeyword( line ) ) { 639 if( debug ) { 640 final String buf = "DEBUG:\t" + file.getPath() + "(" + lineNo + "): " + line ; 641 println( buf ); 642 } 643 644 // 6.3.1.1 (2015/07/10) useAllFind 機能。最後まで検索を続けます。 645 if( useAllFind ) { 646 final String msg = file.getAbsolutePath() + '(' + lineNo + "):" + line ; 647 println( msg ); 648 // 8.1.3.0 (2022/06/03) 保存ファイル指定有り 649 if( StringUtil.isNotNull(saveFile) ){ outWriter.println( msg ); } 650 } 651 else { 652 firstLineNo = lineNo; 653 break; 654 } 655 } 656 } 657 } 658 // 6.3.1.0 (2015/06/28) nioを使用すると UTF-8とShuft-JISで、エラーになる。 659 catch( final CharacterCodingException ex ) { 660 final String errMsg = "文字のエンコード・エラーが発生しました。" + CR 661 + " ファイルのエンコードが指定のエンコードと異なります。" + CR 662// + " [" + file.getPath() + "] , Encode=[" + inEncode + "]" ; 663 + " [" + file.getPath() + "] , Encode=[" + mapEnc + "]" ; // 8.1.3.0 (2022/06/03) 664 // 呼出元で、errAbend処理するので、そのまま、throw しておく。 665 throw new OgCharacterException( errMsg,ex ); // 6.5.0.1 (2016/10/21) 666 } 667 catch( final IOException ex ) { 668 final String errMsg = "キーワードファイル読取エラーが発生しました。" + CR 669// + " [" + file.getPath() + "] , Encode=[" + inEncode + "]" ; 670 + " [" + file.getPath() + "] , Encode=[" + mapEnc + "]" ; // 8.1.3.0 (2022/06/03) 671 // 呼出元で、errAbend処理するので、そのまま、throw しておく。 672 throw new OgRuntimeException( errMsg,ex ); 673 } 674 finally { 675 Closer.ioClose( reader ); 676 } 677 678 return firstLineNo; 679 } 680 681 /** 682 * キーワードが存在しているかどうかをチェックします。 683 * ここでは、ファイルをすべて読み取ってから、チェックします。 684 * よって、複数行にまたがる keyword でのマッチングが可能です。 685 * 686 * @og.rev 4.0.1.0 (2007/12/14) 新規追加 687 * @og.rev 6.4.5.1 (2016/04/28) FileStringのコンストラクター変更 688 * @og.rev 6.4.5.2 (2016/05/06) fukurou.util.FileString から、fukurou.util.FileUtil に移動。 689 * @og.rev 8.1.3.0 (2022/06/03) jarファイル内の検索、オートエンコード対応 690 * 691 * @param file 検索元のファイルオブジェクト 692 * @param mapEnc 検索元のファイルエンコード 693 * 694 * @return 検索元のファイルの文字列化情報(ただし、見つからなければ、null) 695 */ 696// private String findKeywordAsBulk( final File file ) { 697 private String findKeywordAsBulk( final File file,final String mapEnc ) { // 8.1.3.0 (2022/06/03) 698 699 boolean isFind = false; 700 701 // 6.4.5.1 (2016/04/28) FileStringのコンストラクター変更 702// final String line = FileUtil.getValue( file.getPath() , inEncode ); // 6.4.5.2 (2016/05/06) 703 final String line = FileUtil.getValue( file.getPath() , mapEnc ); // 8.1.3.0 (2022/06/03) 704 705 final Matcher mach = pattern.matcher( line ); 706 if( mach.find() ) { 707 if( debug ) { println( "DEBUG:\t" + file.getPath() ); } 708 isFind = true; 709 } 710 711 return isFind ? line : null; 712 } 713 714 /** 715 * キーワードを指定の文字列に置き換えます。 716 * useBackup 属性に true を指定した場合、置き換え後の、backup ファイルは、 717 * オリジナル_backup という名称に変わります。 718 * ここでは、1行づつ読み取りながら、変換処理を行います。 719 * よって、複数行にまたがる keyword でのマッチングは出来ませんが、大きな 720 * ファイル等での置換でも、メモリの使用量は抑えられます。 721 * 722 * @og.rev 4.0.1.0 (2007/12/14) 置換処理を独立させます。 723 * @og.rev 6.2.4.0 (2015/05/15) HEAD,TAIL 追加 724 * @og.rev 6.3.1.0 (2015/06/28) nioを使用すると UTF-8とShuft-JISで、エラーになる。 725 * @og.rev 6.5.0.1 (2016/10/21) CharacterCodingException は、OgCharacterException に変換する。 726 * @og.rev 8.1.3.0 (2022/06/03) jarファイル内の検索、オートエンコード対応 727 * 728 * @param inFile 検索元の入力ファイルオブジェクト 729 * @param outFile 変換後の出力ファイルオブジェクト 730 * @param firstLineNo キーワードが存在した場合の最初の行番号 731 * @param mapEnc 検索元のファイルエンコード 732 */ 733// private void changeKeyword( final File inFile,final File outFile,final int firstLineNo ) { 734 private void changeKeyword( final File inFile,final File outFile,final int firstLineNo,final String mapEnc ) { // 8.1.3.0 (2022/06/03) 735 736// final BufferedReader reader = FileUtil.getBufferedReader( inFile,inEncode ); 737 final BufferedReader reader = FileUtil.getBufferedReader( inFile,mapEnc ); // 8.1.3.0 (2022/06/03) 738 final PrintWriter writer = FileUtil.getPrintWriter( outFile,outEncode ); 739 740 String line = null; 741 try { 742 // 6.2.4.0 (2015/05/15) HEAD,TAIL 追加 743 if( "HEAD".equals( insert ) ) { 744 writer.println( change ); 745 } 746 747 int lineNo = 0; 748 while((line = reader.readLine()) != null) { 749 lineNo++ ; 750 if( lineNo <= skipRowCount ) { continue; } // 6.2.4.0 (2015/05/15) 751 752 if( lineNo >= firstLineNo ) { 753 final Matcher mach = pattern.matcher( line ); 754 755 String chnStr = null; 756 if( "CHANGE".equals( insert ) ) { 757 chnStr = strChange( mach ); 758 } 759 else if( "BEFORE".equals( insert ) ) { 760 chnStr = strBefore( line,mach ); 761 } 762 else if( "AFTER".equals( insert ) ) { 763 chnStr = strAfter( line,mach ); 764 } 765 766 if( chnStr != null ) { 767 line = chnStr; 768 cngCount++ ; // 変換されれば カウント 769 } 770 } 771 writer.println( line ); // readLine() してるので、最後に改行が必要。 772 } 773 774 // 6.2.4.0 (2015/05/15) HEAD,TAIL 追加 775 if( "TAIL".equals( insert ) ) { 776 writer.println( change ); 777 } 778 } 779 // 6.3.1.0 (2015/06/28) nioを使用すると UTF-8とShuft-JISで、エラーになる。 780 catch( final CharacterCodingException ex ) { 781 final String errMsg = "文字のエンコード・エラーが発生しました。" + CR 782 + " ファイルのエンコードが指定のエンコードと異なります。" + CR 783// + " [" + inFile + "] , Encode=[" + inEncode + "]" ; 784 + " [" + inFile + "] , Encode=[" + mapEnc + "]" ; // 8.1.3.0 (2022/06/03) 785 // 呼出元で、errAbend処理するので、そのまま、throw しておく。 786 throw new OgCharacterException( errMsg,ex ); // 6.5.0.1 (2016/10/21) 787 } 788 catch( final IOException ex ) { 789 final String errMsg = "処理中にエラーが発生しました。[" + line + "]" + CR 790// + " [" + inFile + "] , Encode=[" + inEncode + "]" ; 791 + " [" + inFile + "] , Encode=[" + mapEnc + "]" ; // 8.1.3.0 (2022/06/03) 792 // 呼出元で、errAbend処理するので、そのまま、throw しておく。 793 throw new OgRuntimeException( errMsg,ex ); 794 } 795 finally { 796 Closer.ioClose( reader ); 797 Closer.ioClose( writer ); 798 } 799 } 800 /** 801 * キーワードを指定の文字列に置き換えます。 802 * useBackup 属性に true を指定した場合、置き換え後の、backup ファイルは、 803 * オリジナル_backup という名称に変わります。 804 * ここでは、ファイルをすべて読み取ってから、チェックします。 805 * よって、複数行にまたがる keyword でのマッチングが可能です。 806 * 807 * @og.rev 4.0.1.0 (2007/12/14) 置換処理を独立させます。 808 * @og.rev 6.2.4.0 (2015/05/15) HEAD,TAIL 追加 809 * 810 * @param fileLine 検索元の行文字列 811 * @param outFile 出力ファイルオブジェクト 812 */ 813 private void changeKeywordAsBulk( final String fileLine,final File outFile ) { 814 final PrintWriter writer = FileUtil.getPrintWriter( outFile,outEncode ); 815 816 String line = fileLine ; 817 try { 818 // 6.2.4.0 (2015/05/15) HEAD,TAIL 追加 819 if( "HEAD".equals( insert ) ) { 820 writer.println( change ); 821 } 822 823 final Matcher mach = pattern.matcher( line ); 824 825 String chnStr = null; 826 if( "CHANGE".equals( insert ) ) { 827 chnStr = strChange( mach ); 828 } 829 else if( "BEFORE".equals( insert ) ) { 830 chnStr = strBefore( line,mach ); 831 } 832 else if( "AFTER".equals( insert ) ) { 833 chnStr = strAfter( line,mach ); 834 } 835 836 if( chnStr != null ) { 837 line = chnStr; 838 cngCount++ ; // 変換されれば カウント 839 } 840 841 writer.print( line ); // 注意:改行コードは、不要 842 843 // 6.2.4.0 (2015/05/15) HEAD,TAIL 追加 844 if( "TAIL".equals( insert ) ) { 845 writer.println( change ); 846 } 847 } 848 catch( final RuntimeException ex ) { 849 final String errMsg = "処理中にエラーが発生しました。[" + outFile.getPath() + "]" ; 850 // 呼出元で、errAbend処理するので、そのまま、throw しておく。 851 throw new OgRuntimeException( errMsg,ex ); 852 } 853 finally { 854 Closer.ioClose( writer ); 855 } 856 } 857 858 /** 859 * insert が、"CHANGE" の場合の処理結果を求めます。 860 * 変換しなかった場合は、null を返します。 861 * これは、変換カウントを算出する為のフラグ代わりに使用しています。 862 * 863 * @param mach キーワードの正規表現 864 * 865 * @return 変換結果(対象行で無い場合は、null) 866 */ 867 private String strChange( final Matcher mach ) { 868 String line = null; 869 if( mach.find() ) { 870 line = mach.replaceAll( change ); 871 } 872 return line ; 873 } 874 875 /** 876 * insert が、"BEFORE" の場合の処理結果を求めます。 877 * 変換しなかった場合は、null を返します。 878 * これは、変換カウントを算出する為のフラグ代わりに使用しています。 879 * 880 * @param line 検索行 881 * @param mach キーワードの正規表現 882 * 883 * @return 変換結果(対象行で無い場合は、null) 884 */ 885 private String strBefore( final String line , final Matcher mach ) { 886 boolean isChng = false; 887 final StringBuilder buf = new StringBuilder( line.length() ); 888 int indx = 0; 889 while( mach.find() ) { 890 isChng = true; 891 final int strt = mach.start() + insOffset; 892 buf.append( line.substring( indx,strt ) ); 893 buf.append( change ); 894 indx = strt; 895 } 896 897 String rtn = null; 898 if( isChng ) { 899 buf.append( line.substring( indx ) ); 900 rtn = buf.toString(); 901 } 902 903 return rtn ; 904 } 905 906 /** 907 * insert が、"AFTER" の場合の処理結果を求めます。 908 * 変換しなかった場合は、null を返します。 909 * これは、変換カウントを算出する為のフラグ代わりに使用しています。 910 * 911 * @param line 検索行 912 * @param mach キーワードの正規表現 913 * 914 * @return 変換結果(対象行で無い場合は、null) 915 */ 916 private String strAfter( final String line , final Matcher mach ) { 917 boolean isChng = false; 918 final StringBuilder buf = new StringBuilder( line.length() ); 919 int indx = 0; 920 while( mach.find() ) { 921 isChng = true; 922 final int end = mach.end() + insOffset; 923 buf.append( line.substring( indx,end ) ); 924 buf.append( change ); 925 indx = end; 926 } 927 String rtn = null; 928 if( isChng ) { 929 buf.append( line.substring( indx ) ); 930 rtn = buf.toString(); 931 } 932 933 return rtn ; 934 } 935 936 /** 937 * プロセスの処理結果のレポート表現を返します。 938 * 処理プログラム名、入力件数、出力件数などの情報です。 939 * この文字列をそのまま、標準出力に出すことで、結果レポートと出来るような 940 * 形式で出してください。 941 * 942 * @return 処理結果のレポート 943 */ 944 public String report() { 945 if( findCount < cngCount ) { findCount = cngCount; } 946 947 // 7.2.9.5 (2020/11/28) PMD:Consider simply returning the value vs storing it in local variable 'XXXX' 948 return "[" + getClass().getName() + "]" + CR 949// final String report = "[" + getClass().getName() + "]" + CR 950 + TAB + "Search Keyword : " + keyword + CR 951 + TAB + "Search File Count : " + inCount + CR 952 + TAB + "Key Find Count : " + findCount + CR 953 + TAB + "Key Change Count : " + cngCount ; 954 955// return report ; 956 } 957 958 /** 959 * このクラスの使用方法を返します。 960 * 961 * @return このクラスの使用方法 962 * @og.rtnNotNull 963 */ 964 public String usage() { 965 final StringBuilder buf = new StringBuilder( 1400 ) 966 .append( "Process_Grep は、上流から受け取った FileLineModelから、文字列を見つけ出す" ).append( CR ) 967 .append( "ChainProcess インターフェースの実装クラスです。" ).append( CR ) 968 .append( CR ) 969 .append( "正規表現の keyword を上流から受け取った FileLineModel から検索します。" ).append( CR ) 970 .append( "見つかった対象ファイルから、指定の文字列を置換する場合は、-change か" ).append( CR ) 971 .append( "-changeFile で、keyword を置換する文字列を指定して下さい。" ).append( CR ) 972 .append( "置換する文字列には、\t と \n の特殊文字が使用できます。" ).append( CR ) 973 .append( CR ) 974 .append( "処理対象は、通常は、1行づつ読み取りながら処理を行います。存在チェックの場合は、" ).append( CR ) 975 .append( "見つかった時点で処理を中止します。これは、該当箇所をピックアップするのではなく、" ).append( CR ) 976 .append( "存在しているかどうかを判断して、あれば、下流に流すというのが目的だからです。" ).append( CR ) 977 .append( "keyword を、改行を含む正規表現で、検索・置換する場合は、-useBulkRead 属性を" ).append( CR ) 978 .append( "true に設定してください。これは、入力ファイルを一括して読み込みます。" ).append( CR ) 979 .append( "-ignoreCase は、検索時にキーの大文字小文字を無視するように指定します。" ).append( CR ) 980 .append( "-notEquals は、結果(見つかればtrue)を反転(見つからなければtrue)します。" ).append( CR ) 981 .append( "これは、行単位ではなく、ファイル単位に判定しますので、change 指定した場合" ).append( CR ) 982 .append( "でも、対象行は、見つかった行です。ただし、下流に対して、見つからない" ).append( CR ) 983 .append( "場合だけ処理を継続させます。" ).append( CR ) 984 .append( "-inEncode は、入力ファイルのエンコード指定になります。" ).append( CR ) 985 .append( "-outEncode は、出力ファイルのエンコードや、changeFileで指定の置換文字列" ).append( CR ) 986 .append( "ファイルのエンコード指定になります。(changeFile は、必ず 出力ファイルと)" ).append( CR ) 987 .append( "同じエンコードです。" ).append( CR ) 988 .append( "これらのエンコードが無指定の場合は、System.getProperty(\"file.encoding\") " ).append( CR ) 989 .append( "で求まる値を使用します。" ).append( CR ) 990 .append( "-changeFile を使用することで、複数行の文字列に置換することが可能です。" ).append( CR ) 991 .append( CR ) 992 .append( "上流(プロセスチェインのデータは上流から渡されます。)からのLineModel の" ).append( CR ) 993 .append( "ファイルオブジェクトより、指定の文字列が含まれているか検索します。" ).append( CR ) 994 .append( "上流プロセスでは、Name 属性として、『File』を持ち、値は、Fileオブジェクト" ).append( CR ) 995 .append( "である、Process_FileSearch を使用するのが、便利です。それ以外のクラスを" ).append( CR ) 996 .append( "使用する場合でも、Name属性と、File オブジェクトを持つ LineModel を受け渡し" ).append( CR ) 997 .append( "できれば、使用可能です。" ).append( CR ) 998 .append( CR ) 999 .append( "引数文字列中に空白を含む場合は、ダブルコーテーション(\"\") で括って下さい。" ).append( CR ) 1000 .append( "引数文字列の 『=』の前後には、空白は挟めません。必ず、-key=value の様に" ).append( CR ) 1001 .append( "繋げてください。" ).append( CR ) 1002 .append( CR ).append( CR ) 1003 .append( getArgument().usage() ).append( CR ); 1004 1005 return buf.toString(); 1006 } 1007 1008 /** 1009 * このクラスは、main メソッドから実行できません。 1010 * 1011 * @param args コマンド引数配列 1012 */ 1013 public static void main( final String[] args ) { 1014 LogWriter.log( new Process_Grep().usage() ); 1015 } 1016}