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 * @og.rev 8.5.2.0 (2023/07/14) -change=置換文字列 の指定がなくても findCount がセットされるように対応 442 * 443 * @param file 検索元のファイルオブジェクト 444 */ 445 private void findJarKeyword( final File file ) { 446 JarFile jarFile = null; 447 448 try { 449 jarFile = new JarFile( file ); 450 451 final Enumeration<JarEntry> flEnum = jarFile.entries() ; // Generics警告対応 452 while( flEnum.hasMoreElements() ) { 453 final JarEntry ent = flEnum.nextElement(); // Generics警告対応 454 if( ent.isDirectory() ) { continue; } 455 456 final String fileName = ent.getName(); // jarファイル内のファイル 457 458 // 拡張子によるエンコード指定 459 final String mapEnc = getEncode( fileName ); 460 // 該当するエンコード無し 461 if( "-".equals(mapEnc) ) { continue; } 462 463 final String lowName = fileName.toLowerCase( Locale.JAPAN ); 464 if( ( jarPrefix == null || lowName.startsWith( jarPrefix ) ) && 465 ( jarSuffix == null || lowName.endsWith( jarSuffix ) ) && 466 ( jarInstr == null || lowName.contains( jarInstr ) ) ) { 467 468 InputStream stream = null; 469 try { 470 stream = jarFile.getInputStream( ent ) ; 471 472 final BufferedReader reader = new BufferedReader( new InputStreamReader( stream, mapEnc ) ); 473 474 final CommentLineParser clp = useOmitCmnt ? new CommentLineParser( FileInfo.getSUFIX( fileName ) ) : null; 475 try { 476 String line ; 477 int lineNo = 0; 478 while((line = reader.readLine()) != null) { 479 lineNo++ ; // 注意:ここで返す行数は、コメント行を含む行数とする 480 481 // useOmitCmnt 機能(コメント行を削除する処理を入れる) 482 if( useOmitCmnt ) { 483 line = clp.line( line ); 484 if( line == null ) { continue; } // 戻り値が null の場合は、行として不成立 485 } 486 487 // キーワードを含むかどうか判定 488 if( isKeyword( line ) ) { 489 final String msg = file.getPath() + "\\" + fileName + '(' + lineNo + "):" + line ; 490 if( debug ) { 491 final String buf = "DEBUG:\t" + msg ; 492 println( buf ); 493 } 494 // useAllFind=true 相当の処理のみ行う 495 println( msg ); 496 findCount++ ; // 8.5.2.0 (2023/07/14) Add 497 // 保存ファイル指定有り 498 if( StringUtil.isNotNull(saveFile) ){ outWriter.println( msg ); } 499 500 // useAllFind 機能(最後まで検索を続ける) 501 if( !useAllFind ) { break; } 502 } 503 } 504 } 505 // nioを使用すると UTF-8とShuft-JISで、エラーになる 506 catch( final CharacterCodingException ex ) { 507 final String errMsg = "文字のエンコード・エラーが発生しました。" + CR 508 + " ファイルのエンコードが指定のエンコードと異なります。" + CR 509 + " [" + file.getPath() + "] , Encode=[" + mapEnc + "]" ; 510 // 呼出元で errAbend 処理するので、そのまま throw しておく 511 throw new OgCharacterException( errMsg,ex ); 512 } 513 catch( final IOException ex ) { 514 final String errMsg = "キーワードファイル読取エラーが発生しました。" + CR 515 + " [" + file.getPath() + "] , Encode=[" + mapEnc + "]" ; 516 // 呼出元で errAbend 処理するので、そのまま throw しておく 517 throw new OgRuntimeException( errMsg,ex ); 518 } 519 finally { 520 Closer.ioClose( reader ); 521 } 522 } 523 finally { 524 Closer.ioClose( stream ); 525 } 526 } 527 } 528 } 529 catch( final IOException ex ) { 530 final String errMsg = "キーワードファイル読取エラーが発生しました。" + CR 531 + " [" + file.getPath() + "] , Encode=[" + inEncode + "]" ; 532 // 呼出元で errAbend 処理するので、そのまま throw しておく 533 throw new OgRuntimeException( errMsg,ex ); 534 } 535 finally { 536 Closer.zipClose( jarFile ); 537 } 538 } 539 540 /** 541 * 拡張子をエンコードに変換します。 542 * 543 * @og.rev 8.1.3.0 (2022/06/03) jarファイル内の検索、オートエンコード対応 544 * 545 * @param file 検索元のファイル 546 * @return エンコード 547 */ 548 private String getEncode( final File file ) { 549 return getEncode( file.getName() ); 550 } 551 552 /** 553 * 拡張子をエンコードに変換します。 554 * 555 * @og.rev 8.1.3.0 (2022/06/03) jarファイル内の検索、オートエンコード対応 556 * 557 * @param fileName 検索元のファイル名 558 * @return エンコード 559 */ 560 private String getEncode( final String fileName ) { 561 // 自動判定 562 if( AUTO_ENCODE.equalsIgnoreCase( inEncode ) ) { 563 final String sufix = FileInfo.getSUFIX( fileName ); // 拡張子取得 564 return StringUtil.nval( EXT2ENC.get( sufix ), "-" ); 565 } 566 else { 567 return StringUtil.nval( inEncode, "-" ); 568 } 569 } 570 571 /** 572 * 該当の行にキーワードを含むかどうか判定します。 573 * 574 * @og.rev 8.1.3.0 (2022/06/03) jarファイル内の検索、オートエンコード対応 575 * 576 * @param line 検索元のファイルの行 577 * @return キーワードを含むかどうか[true/false] 578 */ 579 private boolean isKeyword( final String line ) { 580 // 正規表現を使用する 581 if( useRegexp ){ 582 final Matcher mach = pattern.matcher( line ); 583 return mach.find(); 584 } 585 // 正規表現を使用しない 586 else { 587 // 大文字小文字を区別しない 588 if( ignoreCase ) { 589 return line.toLowerCase( Locale.JAPAN ).contains( keyword ); 590 } 591 // 大文字小文字を区別する 592 else { 593 return line.contains( keyword ); 594 } 595 } 596 } 597 598 /** 599 * キーワードが存在しているかどうかをチェックします。 600 * ここでは、1行づつ読み取りながら、最初に見つかった時点で制御を返します。 601 * よって、複数行にまたがる keyword でのマッチングは出来ませんが、大きな 602 * ファイル等での検索には、効率的です。 603 * 604 * @og.rev 4.0.1.0 (2007/12/14) 新規追加 605 * @og.rev 6.3.1.0 (2015/06/28) nioを使用すると UTF-8とShuft-JISで、エラーになる。 606 * @og.rev 6.3.1.0 (2015/06/28) errAbend属性追加。 607 * @og.rev 6.3.1.1 (2015/07/10) useOmitCmnt、useAllFind 機能追加 608 * @og.rev 6.4.0.2 (2015/12/11) CommentLineParser 改造。 609 * @og.rev 6.5.0.1 (2016/10/21) CharacterCodingException は、OgCharacterException に変換する。 610 * @og.rev 8.1.3.0 (2022/06/03) jarファイル内の検索、オートエンコード対応 611 * @og.rev 8.5.2.0 (2023/07/14) -change=置換文字列 の指定がなくても findCount がセットされるように対応 612 * 613 * @param file 検索元のファイルオブジェクト 614 * @param mapEnc 検索元のファイルエンコード 615 * 616 * @return 最初に見つかった行番号(見つからなければ、-1 を返す) 617 */ 618// private int findKeyword( final File file ) { 619 private int findKeyword( final File file ,final String mapEnc ) { // 8.1.3.0 (2022/06/03) 620 int firstLineNo = -1; 621// final BufferedReader reader = FileUtil.getBufferedReader( file,inEncode ); 622 final BufferedReader reader = FileUtil.getBufferedReader( file,mapEnc ); // 8.1.3.0 (2022/06/03) 623 624 // 6.4.0.2 (2015/12/11) CommentLineParser 改造 625 final CommentLineParser clp = useOmitCmnt ? new CommentLineParser( FileInfo.getSUFIX( file ) ) : null; 626 try { 627 String line ; 628 int lineNo = 0; 629 while((line = reader.readLine()) != null) { 630 lineNo++ ; // 注意:ここで返す行数は、コメント行を含む行数とする。 631 632 // 6.3.1.1 (2015/07/10) useOmitCmnt 機能。コメント行を削除する処理を入れる。 633 if( useOmitCmnt ) { 634 line = clp.line( line ); 635 if( line == null ) { continue; } // 戻り値が null の場合は、行として不成立 636 } 637 // 8.1.3.0 (2022/06/03) Modify 638// final Matcher mach = pattern.matcher( line ); 639// if( mach.find() ) { 640 // キーワードを含むかどうか判定 641 if( isKeyword( line ) ) { 642 if( debug ) { 643 final String buf = "DEBUG:\t" + file.getPath() + "(" + lineNo + "): " + line ; 644 println( buf ); 645 } 646 647 // 6.3.1.1 (2015/07/10) useAllFind 機能。最後まで検索を続けます。 648 if( useAllFind ) { 649 final String msg = file.getAbsolutePath() + '(' + lineNo + "):" + line ; 650 println( msg ); 651 findCount++ ; // 8.5.2.0 (2023/07/14) Add 652 // 8.1.3.0 (2022/06/03) 保存ファイル指定有り 653 if( StringUtil.isNotNull(saveFile) ){ outWriter.println( msg ); } 654 } 655 else { 656 firstLineNo = lineNo; 657 break; 658 } 659 } 660 } 661 } 662 // 6.3.1.0 (2015/06/28) nioを使用すると UTF-8とShuft-JISで、エラーになる。 663 catch( final CharacterCodingException ex ) { 664 final String errMsg = "文字のエンコード・エラーが発生しました。" + CR 665 + " ファイルのエンコードが指定のエンコードと異なります。" + CR 666// + " [" + file.getPath() + "] , Encode=[" + inEncode + "]" ; 667 + " [" + file.getPath() + "] , Encode=[" + mapEnc + "]" ; // 8.1.3.0 (2022/06/03) 668 // 呼出元で、errAbend処理するので、そのまま、throw しておく。 669 throw new OgCharacterException( errMsg,ex ); // 6.5.0.1 (2016/10/21) 670 } 671 catch( final IOException ex ) { 672 final String errMsg = "キーワードファイル読取エラーが発生しました。" + CR 673// + " [" + file.getPath() + "] , Encode=[" + inEncode + "]" ; 674 + " [" + file.getPath() + "] , Encode=[" + mapEnc + "]" ; // 8.1.3.0 (2022/06/03) 675 // 呼出元で、errAbend処理するので、そのまま、throw しておく。 676 throw new OgRuntimeException( errMsg,ex ); 677 } 678 finally { 679 Closer.ioClose( reader ); 680 } 681 682 return firstLineNo; 683 } 684 685 /** 686 * キーワードが存在しているかどうかをチェックします。 687 * ここでは、ファイルをすべて読み取ってから、チェックします。 688 * よって、複数行にまたがる keyword でのマッチングが可能です。 689 * 690 * @og.rev 4.0.1.0 (2007/12/14) 新規追加 691 * @og.rev 6.4.5.1 (2016/04/28) FileStringのコンストラクター変更 692 * @og.rev 6.4.5.2 (2016/05/06) fukurou.util.FileString から、fukurou.util.FileUtil に移動。 693 * @og.rev 8.1.3.0 (2022/06/03) jarファイル内の検索、オートエンコード対応 694 * @og.rev 8.5.2.0 (2023/07/14) -change=置換文字列 の指定がなくても findCount がセットされるように対応 695 * 696 * @param file 検索元のファイルオブジェクト 697 * @param mapEnc 検索元のファイルエンコード 698 * 699 * @return 検索元のファイルの文字列化情報(ただし、見つからなければ、null) 700 */ 701// private String findKeywordAsBulk( final File file ) { 702 private String findKeywordAsBulk( final File file,final String mapEnc ) { // 8.1.3.0 (2022/06/03) 703 704 boolean isFind = false; 705 706 // 6.4.5.1 (2016/04/28) FileStringのコンストラクター変更 707// final String line = FileUtil.getValue( file.getPath() , inEncode ); // 6.4.5.2 (2016/05/06) 708 final String line = FileUtil.getValue( file.getPath() , mapEnc ); // 8.1.3.0 (2022/06/03) 709 710 final Matcher mach = pattern.matcher( line ); 711 if( mach.find() ) { 712 if( debug ) { println( "DEBUG:\t" + file.getPath() ); } 713 findCount++ ; // 8.5.2.0 (2023/07/14) Add 714 isFind = true; 715 } 716 717 return isFind ? line : null; 718 } 719 720 /** 721 * キーワードを指定の文字列に置き換えます。 722 * useBackup 属性に true を指定した場合、置き換え後の、backup ファイルは、 723 * オリジナル_backup という名称に変わります。 724 * ここでは、1行づつ読み取りながら、変換処理を行います。 725 * よって、複数行にまたがる keyword でのマッチングは出来ませんが、大きな 726 * ファイル等での置換でも、メモリの使用量は抑えられます。 727 * 728 * @og.rev 4.0.1.0 (2007/12/14) 置換処理を独立させます。 729 * @og.rev 6.2.4.0 (2015/05/15) HEAD,TAIL 追加 730 * @og.rev 6.3.1.0 (2015/06/28) nioを使用すると UTF-8とShuft-JISで、エラーになる。 731 * @og.rev 6.5.0.1 (2016/10/21) CharacterCodingException は、OgCharacterException に変換する。 732 * @og.rev 8.1.3.0 (2022/06/03) jarファイル内の検索、オートエンコード対応 733 * 734 * @param inFile 検索元の入力ファイルオブジェクト 735 * @param outFile 変換後の出力ファイルオブジェクト 736 * @param firstLineNo キーワードが存在した場合の最初の行番号 737 * @param mapEnc 検索元のファイルエンコード 738 */ 739// private void changeKeyword( final File inFile,final File outFile,final int firstLineNo ) { 740 private void changeKeyword( final File inFile,final File outFile,final int firstLineNo,final String mapEnc ) { // 8.1.3.0 (2022/06/03) 741 742// final BufferedReader reader = FileUtil.getBufferedReader( inFile,inEncode ); 743 final BufferedReader reader = FileUtil.getBufferedReader( inFile,mapEnc ); // 8.1.3.0 (2022/06/03) 744 final PrintWriter writer = FileUtil.getPrintWriter( outFile,outEncode ); 745 746 String line = null; 747 try { 748 // 6.2.4.0 (2015/05/15) HEAD,TAIL 追加 749 if( "HEAD".equals( insert ) ) { 750 writer.println( change ); 751 } 752 753 int lineNo = 0; 754 while((line = reader.readLine()) != null) { 755 lineNo++ ; 756 if( lineNo <= skipRowCount ) { continue; } // 6.2.4.0 (2015/05/15) 757 758 if( lineNo >= firstLineNo ) { 759 final Matcher mach = pattern.matcher( line ); 760 761 String chnStr = null; 762 if( "CHANGE".equals( insert ) ) { 763 chnStr = strChange( mach ); 764 } 765 else if( "BEFORE".equals( insert ) ) { 766 chnStr = strBefore( line,mach ); 767 } 768 else if( "AFTER".equals( insert ) ) { 769 chnStr = strAfter( line,mach ); 770 } 771 772 if( chnStr != null ) { 773 line = chnStr; 774 cngCount++ ; // 変換されれば カウント 775 } 776 } 777 writer.println( line ); // readLine() してるので、最後に改行が必要。 778 } 779 780 // 6.2.4.0 (2015/05/15) HEAD,TAIL 追加 781 if( "TAIL".equals( insert ) ) { 782 writer.println( change ); 783 } 784 } 785 // 6.3.1.0 (2015/06/28) nioを使用すると UTF-8とShuft-JISで、エラーになる。 786 catch( final CharacterCodingException ex ) { 787 final String errMsg = "文字のエンコード・エラーが発生しました。" + CR 788 + " ファイルのエンコードが指定のエンコードと異なります。" + CR 789// + " [" + inFile + "] , Encode=[" + inEncode + "]" ; 790 + " [" + inFile + "] , Encode=[" + mapEnc + "]" ; // 8.1.3.0 (2022/06/03) 791 // 呼出元で、errAbend処理するので、そのまま、throw しておく。 792 throw new OgCharacterException( errMsg,ex ); // 6.5.0.1 (2016/10/21) 793 } 794 catch( final IOException ex ) { 795 final String errMsg = "処理中にエラーが発生しました。[" + line + "]" + CR 796// + " [" + inFile + "] , Encode=[" + inEncode + "]" ; 797 + " [" + inFile + "] , Encode=[" + mapEnc + "]" ; // 8.1.3.0 (2022/06/03) 798 // 呼出元で、errAbend処理するので、そのまま、throw しておく。 799 throw new OgRuntimeException( errMsg,ex ); 800 } 801 finally { 802 Closer.ioClose( reader ); 803 Closer.ioClose( writer ); 804 } 805 } 806 /** 807 * キーワードを指定の文字列に置き換えます。 808 * useBackup 属性に true を指定した場合、置き換え後の、backup ファイルは、 809 * オリジナル_backup という名称に変わります。 810 * ここでは、ファイルをすべて読み取ってから、チェックします。 811 * よって、複数行にまたがる keyword でのマッチングが可能です。 812 * 813 * @og.rev 4.0.1.0 (2007/12/14) 置換処理を独立させます。 814 * @og.rev 6.2.4.0 (2015/05/15) HEAD,TAIL 追加 815 * 816 * @param fileLine 検索元の行文字列 817 * @param outFile 出力ファイルオブジェクト 818 */ 819 private void changeKeywordAsBulk( final String fileLine,final File outFile ) { 820 final PrintWriter writer = FileUtil.getPrintWriter( outFile,outEncode ); 821 822 String line = fileLine ; 823 try { 824 // 6.2.4.0 (2015/05/15) HEAD,TAIL 追加 825 if( "HEAD".equals( insert ) ) { 826 writer.println( change ); 827 } 828 829 final Matcher mach = pattern.matcher( line ); 830 831 String chnStr = null; 832 if( "CHANGE".equals( insert ) ) { 833 chnStr = strChange( mach ); 834 } 835 else if( "BEFORE".equals( insert ) ) { 836 chnStr = strBefore( line,mach ); 837 } 838 else if( "AFTER".equals( insert ) ) { 839 chnStr = strAfter( line,mach ); 840 } 841 842 if( chnStr != null ) { 843 line = chnStr; 844 cngCount++ ; // 変換されれば カウント 845 } 846 847 writer.print( line ); // 注意:改行コードは、不要 848 849 // 6.2.4.0 (2015/05/15) HEAD,TAIL 追加 850 if( "TAIL".equals( insert ) ) { 851 writer.println( change ); 852 } 853 } 854 catch( final RuntimeException ex ) { 855 final String errMsg = "処理中にエラーが発生しました。[" + outFile.getPath() + "]" ; 856 // 呼出元で、errAbend処理するので、そのまま、throw しておく。 857 throw new OgRuntimeException( errMsg,ex ); 858 } 859 finally { 860 Closer.ioClose( writer ); 861 } 862 } 863 864 /** 865 * insert が、"CHANGE" の場合の処理結果を求めます。 866 * 変換しなかった場合は、null を返します。 867 * これは、変換カウントを算出する為のフラグ代わりに使用しています。 868 * 869 * @param mach キーワードの正規表現 870 * 871 * @return 変換結果(対象行で無い場合は、null) 872 */ 873 private String strChange( final Matcher mach ) { 874 String line = null; 875 if( mach.find() ) { 876 line = mach.replaceAll( change ); 877 } 878 return line ; 879 } 880 881 /** 882 * insert が、"BEFORE" の場合の処理結果を求めます。 883 * 変換しなかった場合は、null を返します。 884 * これは、変換カウントを算出する為のフラグ代わりに使用しています。 885 * 886 * @param line 検索行 887 * @param mach キーワードの正規表現 888 * 889 * @return 変換結果(対象行で無い場合は、null) 890 */ 891 private String strBefore( final String line , final Matcher mach ) { 892 boolean isChng = false; 893 final StringBuilder buf = new StringBuilder( line.length() ); 894 int indx = 0; 895 while( mach.find() ) { 896 isChng = true; 897 final int strt = mach.start() + insOffset; 898 buf.append( line.substring( indx,strt ) ); 899 buf.append( change ); 900 indx = strt; 901 } 902 903 String rtn = null; 904 if( isChng ) { 905 buf.append( line.substring( indx ) ); 906 rtn = buf.toString(); 907 } 908 909 return rtn ; 910 } 911 912 /** 913 * insert が、"AFTER" の場合の処理結果を求めます。 914 * 変換しなかった場合は、null を返します。 915 * これは、変換カウントを算出する為のフラグ代わりに使用しています。 916 * 917 * @param line 検索行 918 * @param mach キーワードの正規表現 919 * 920 * @return 変換結果(対象行で無い場合は、null) 921 */ 922 private String strAfter( final String line , final Matcher mach ) { 923 boolean isChng = false; 924 final StringBuilder buf = new StringBuilder( line.length() ); 925 int indx = 0; 926 while( mach.find() ) { 927 isChng = true; 928 final int end = mach.end() + insOffset; 929 buf.append( line.substring( indx,end ) ); 930 buf.append( change ); 931 indx = end; 932 } 933 String rtn = null; 934 if( isChng ) { 935 buf.append( line.substring( indx ) ); 936 rtn = buf.toString(); 937 } 938 939 return rtn ; 940 } 941 942 /** 943 * プロセスの処理結果のレポート表現を返します。 944 * 処理プログラム名、入力件数、出力件数などの情報です。 945 * この文字列をそのまま、標準出力に出すことで、結果レポートと出来るような 946 * 形式で出してください。 947 * 948 * @return 処理結果のレポート 949 */ 950 public String report() { 951 if( findCount < cngCount ) { findCount = cngCount; } 952 953 // 7.2.9.5 (2020/11/28) PMD:Consider simply returning the value vs storing it in local variable 'XXXX' 954 return "[" + getClass().getName() + "]" + CR 955// final String report = "[" + getClass().getName() + "]" + CR 956 + TAB + "Search Keyword : " + keyword + CR 957 + TAB + "Search File Count : " + inCount + CR 958 + TAB + "Key Find Count : " + findCount + CR 959 + TAB + "Key Change Count : " + cngCount ; 960 961// return report ; 962 } 963 964 /** 965 * このクラスの使用方法を返します。 966 * 967 * @return このクラスの使用方法 968 * @og.rtnNotNull 969 */ 970 public String usage() { 971 final StringBuilder buf = new StringBuilder( 1400 ) 972 .append( "Process_Grep は、上流から受け取った FileLineModelから、文字列を見つけ出す" ).append( CR ) 973 .append( "ChainProcess インターフェースの実装クラスです。" ).append( CR ) 974 .append( CR ) 975 .append( "正規表現の keyword を上流から受け取った FileLineModel から検索します。" ).append( CR ) 976 .append( "見つかった対象ファイルから、指定の文字列を置換する場合は、-change か" ).append( CR ) 977 .append( "-changeFile で、keyword を置換する文字列を指定して下さい。" ).append( CR ) 978 .append( "置換する文字列には、\t と \n の特殊文字が使用できます。" ).append( CR ) 979 .append( CR ) 980 .append( "処理対象は、通常は、1行づつ読み取りながら処理を行います。存在チェックの場合は、" ).append( CR ) 981 .append( "見つかった時点で処理を中止します。これは、該当箇所をピックアップするのではなく、" ).append( CR ) 982 .append( "存在しているかどうかを判断して、あれば、下流に流すというのが目的だからです。" ).append( CR ) 983 .append( "keyword を、改行を含む正規表現で、検索・置換する場合は、-useBulkRead 属性を" ).append( CR ) 984 .append( "true に設定してください。これは、入力ファイルを一括して読み込みます。" ).append( CR ) 985 .append( "-ignoreCase は、検索時にキーの大文字小文字を無視するように指定します。" ).append( CR ) 986 .append( "-notEquals は、結果(見つかればtrue)を反転(見つからなければtrue)します。" ).append( CR ) 987 .append( "これは、行単位ではなく、ファイル単位に判定しますので、change 指定した場合" ).append( CR ) 988 .append( "でも、対象行は、見つかった行です。ただし、下流に対して、見つからない" ).append( CR ) 989 .append( "場合だけ処理を継続させます。" ).append( CR ) 990 .append( "-inEncode は、入力ファイルのエンコード指定になります。" ).append( CR ) 991 .append( "-outEncode は、出力ファイルのエンコードや、changeFileで指定の置換文字列" ).append( CR ) 992 .append( "ファイルのエンコード指定になります。(changeFile は、必ず 出力ファイルと)" ).append( CR ) 993 .append( "同じエンコードです。" ).append( CR ) 994 .append( "これらのエンコードが無指定の場合は、System.getProperty(\"file.encoding\") " ).append( CR ) 995 .append( "で求まる値を使用します。" ).append( CR ) 996 .append( "-changeFile を使用することで、複数行の文字列に置換することが可能です。" ).append( CR ) 997 .append( CR ) 998 .append( "上流(プロセスチェインのデータは上流から渡されます。)からのLineModel の" ).append( CR ) 999 .append( "ファイルオブジェクトより、指定の文字列が含まれているか検索します。" ).append( CR ) 1000 .append( "上流プロセスでは、Name 属性として、『File』を持ち、値は、Fileオブジェクト" ).append( CR ) 1001 .append( "である、Process_FileSearch を使用するのが、便利です。それ以外のクラスを" ).append( CR ) 1002 .append( "使用する場合でも、Name属性と、File オブジェクトを持つ LineModel を受け渡し" ).append( CR ) 1003 .append( "できれば、使用可能です。" ).append( CR ) 1004 .append( CR ) 1005 .append( "引数文字列中に空白を含む場合は、ダブルコーテーション(\"\") で括って下さい。" ).append( CR ) 1006 .append( "引数文字列の 『=』の前後には、空白は挟めません。必ず、-key=value の様に" ).append( CR ) 1007 .append( "繋げてください。" ).append( CR ) 1008 .append( CR ).append( CR ) 1009 .append( getArgument().usage() ).append( CR ); 1010 1011 return buf.toString(); 1012 } 1013 1014 /** 1015 * このクラスは、main メソッドから実行できません。 1016 * 1017 * @param args コマンド引数配列 1018 */ 1019 public static void main( final String[] args ) { 1020 LogWriter.log( new Process_Grep().usage() ); 1021 } 1022}