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