001 /*
002 * Copyright (c) 2009 The openGion Project.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
013 * either express or implied. See the License for the specific language
014 * governing permissions and limitations under the License.
015 */
016 package org.opengion.fukurou.process;
017
018 import org.opengion.fukurou.util.Argument;
019 import org.opengion.fukurou.util.FileUtil;
020 import org.opengion.fukurou.util.FileString;
021 import org.opengion.fukurou.util.Closer ;
022 import org.opengion.fukurou.util.StringUtil ;
023 import org.opengion.fukurou.util.LogWriter;
024
025 import java.util.Map ;
026 import java.util.LinkedHashMap ;
027 import java.util.List ;
028 import java.util.ArrayList ;
029
030 import java.io.File;
031 import java.io.PrintWriter;
032 import java.io.BufferedReader;
033 import java.io.IOException;
034
035 /**
036 * Process_GrepChange は、上流から受け取っ?FileLineModelから、語句?
037 * 置換する?ChainProcess インターフェースの実?ラスです?
038 *
039 * Process_Grep との違いは、チェ?するファイルのコピ??キーワードが存在
040 * しなくと?作?することと、検索キーに正規表現が使えな???行置き換えが
041 * 出来な?とです?
042 *
043 * keywordFile より、置換する語句を含?ーと値のペアー(タブ区?)を読取り?
044 * 対象とする語句を置換します?
045 * keywordFile に、タブが含まれな?や、?頭にタブが存在して?場合??
046 * そ?行を読み飛?します?また?区?タブ?何?存在しても構いません?
047 * ただし?タブで区?た前(キー)と後ろ(値)は、trim() されます?で、スペ?ス
048 * が前後に存在して?場合?、ご注意く???
049 * 置換文?値)は、\t と \n の特殊文字が使用できます?
050 * こ? GrepChange では、語句に、正規表現は使用できません。正規表現のキーワー?
051 * ?字?を?行???と置き換える場合?、Process_Grep を使用してください?
052 * こ?プログラ?は、上流から受け取っ?FileLineModel のファイルに対して?
053 * 置き換えた結果も?同じファイルにセーブします?
054 * ??ファイルを保存したい場合?、予めバックア??を取得しておいてください?
055 * -inEncode は、?力ファイルのエンコード指定になります?
056 * -outEncode は、?力ファイルのエンコードや、キーワードファイルの
057 * エンコード指定になります?(keywordFile は、? 出力ファイルと同じエンコードです?)
058 * これら?エンコードが無??場合?、System.getProperty("file.encoding") で
059 * 求まる?を使用します?
060 *
061 * 上流?ロセスでは、Name 属?として、?File』を持ち、?は、Fileオブジェク?
062 * である、Process_FileSearch を使用するのが?便利です?それ以外?クラス?
063 * 使用する場合でも?Name属?と、File オブジェクトを持つ LineModel を受け渡?
064 * できれば、使用可能です?
065 *
066 * 引数??中にスペ?スを含??合?、ダブルコー??ション("") で括って下さ??
067 * 引数??の ?』?前後には、スペ?スは挟めません。??key=value の様に
068 * 繋げてください?
069 *
070 * Process_GrepChange -keyword=検索?? -ignoreCase=true -outfile=OUTFILE -encode=UTF-8
071 *
072 * -keywordFile=キーワー? ?置換する語句を含?ーと値のペアー(タブ区?)
073 * [-ignoreCase=大?小文?] ?検索時に大?小文字を区別しな?true)かど?(初期値:false[区別する])
074 * [-isChange=置換可否 ] ?置換??実施する(true)かど?(初期値:置換する[true])
075 * [-inEncode=入力エンコー?] ??力ファイルのエンコードタイ?
076 * [-outEncode=出力エンコード] ??力ファイル?ーワードファイルのエンコードタイ?
077 * [-display=false|true ] ?結果を標準?力に表示する(true)かしな?false)?初期値:false[表示しない])
078 * [-debug=false|true ] ?デバッグ??を標準?力に表示する(true)かしな?false)?初期値:false[表示しない])
079 *
080 * @version 4.0
081 * @author Kazuhiko Hasegawa
082 * @since JDK5.0,
083 */
084 public class Process_GrepChange extends AbstractProcess implements ChainProcess {
085 private String[] keyword = null;
086 private String[] change = null;
087 private boolean ignoreCase = false;
088 private boolean isChange = true; // 5.1.2.0 (2010/01/01) 置換するかど?を指定可能にする
089 private String inEncode = null;
090 private String outEncode = null;
091 private boolean display = false; // 表示しな?
092 private boolean debug = false; // 5.7.3.0 (2014/02/07) ????
093
094 private int inCount = 0;
095 private int findCount = 0;
096 private int cngCount = 0;
097
098 private static final Map<String,String> mustProparty ; // ?プロパティ???チェ?用 Map
099 private static final Map<String,String> usableProparty ; // ?プロパティ?整合?チェ? Map
100
101 static {
102 mustProparty = new LinkedHashMap<String,String>();
103 mustProparty.put( "keywordFile", "置換する語句を含?ーと値のペアー(タブ区?)(??)" );
104
105 usableProparty = new LinkedHashMap<String,String>();
106 usableProparty.put( "ignoreCase", "検索時に大?小文字を区別しな?true)かど?? +
107 CR + "(初期値:区別する[false])" );
108 usableProparty.put( "isChange", "置換??実施する(true)かど?" +
109 CR + "(初期値:置換する[true])" );
110 usableProparty.put( "inEncode", "入力ファイルのエンコードタイ? );
111 usableProparty.put( "outEncode", "出力ファイル?ーワードファイルのエンコードタイ? );
112 usableProparty.put( "display", "結果を標準?力に表示する(true)かしな?false)? +
113 CR + "(初期値:false:表示しな?" );
114 usableProparty.put( "debug", "????を標準?力に表示する(true)かしな?false)? +
115 CR + "(初期値:false:表示しな?" ); // 5.7.3.0 (2014/02/07) ????
116 }
117
118 /**
119 * ?ォルトコンストラクター?
120 * こ?クラスは、動??されます??ォルトコンストラクターで?
121 * super クラスに対して、?な初期化を行っておきます?
122 *
123 */
124 public Process_GrepChange() {
125 super( "org.opengion.fukurou.process.Process_GrepChange",mustProparty,usableProparty );
126 }
127
128 /**
129 * プロセスの初期化を行います?初めに??、呼び出されます?
130 * 初期処?ファイルオープン??オープン?に使用します?
131 *
132 * @og.rev 5.1.2.0 (2010/01/01) 置換するかど?を指定可能にする(isChange)属?追?
133 *
134 * @param paramProcess ??タベ?スの接続???などを持って?オブジェク?
135 */
136 public void init( final ParamProcess paramProcess ) {
137 Argument arg = getArgument();
138
139 String keywordFile = arg.getProparty("keywordFile" );
140 ignoreCase = arg.getProparty("ignoreCase",ignoreCase);
141 isChange = arg.getProparty("isChange",isChange); // 5.1.2.0 (2010/01/01)
142 inEncode = arg.getProparty("inEncode",System.getProperty("file.encoding"));
143 outEncode = arg.getProparty("outEncode",System.getProperty("file.encoding"));
144 display = arg.getProparty("display",display);
145 debug = arg.getProparty("debug",debug); // 5.7.3.0 (2014/02/07) ????
146 // if( debug ) { println( arg.toString() ); } // 5.7.3.0 (2014/02/07) ????
147
148 FileString fs = new FileString();
149 fs.setFilename( keywordFile );
150 fs.setEncode( outEncode );
151 String[] lines = fs.getValue( "\n" );
152 int len = lines.length;
153 if( len == 0 ) {
154 String errMsg = "keywordFile の??読み取れませんでした?" + keywordFile + "]" ;
155 throw new RuntimeException( errMsg );
156 }
157
158 println( "keywordFile を?" + len + "件読み取りました? );
159 List<String> keyList = new ArrayList<String>( len );
160 List<String> cngList = new ArrayList<String>( len );
161
162 for( int i=0; i<len; i++ ) {
163 // String line = lines[i].trim();
164 String line = lines[i];
165 int indx = line.indexOf( '\t' );
166 if( indx <= 0 ) { continue ; } // TAB が?頭??存在しな??読み飛?す?
167 keyList.add( line.substring( 0,indx ).trim() );
168 String cng = line.substring( indx+1 ).trim();
169 cng = StringUtil.replace( cng,"\\n",CR );
170 cng = StringUtil.replace( cng,"\\t","\t" );
171 cngList.add( cng );
172 }
173 keyword = keyList.toArray( new String[keyList.size()] );
174 change = cngList.toArray( new String[cngList.size()] );
175 }
176
177 /**
178 * プロセスの終?行います??に??、呼び出されます?
179 * 終???ファイルクローズ??クローズ?に使用します?
180 *
181 * @param isOK ト?タルで、OK?たかど?[true:成功/false:失敗]
182 */
183 public void end( final boolean isOK ) {
184 // ここでは処?行いません?
185 }
186
187 /**
188 * 引数の LineModel を??るメソ?です?
189 * 変換処?? LineModel を返します?
190 * 後続??行わな?????タのフィルタリングを行う場?は?
191 * null ??タを返します?つまり?null ??タは、後続??行わな?
192 * フラグの代わりにも使用して?す?
193 * なお?変換処?? LineModel と、オリジナルの LineModel が?
194 * 同?、コピ?(クローン)か?、各処?ソ??決めて?す?
195 * ドキュメントに明記されて???合?、副作用が問題になる?合??
196 * ???とに自?コピ?(クローン)して下さ??
197 *
198 * @og.rev 4.0.0.0 (2007/11/28) メソ?の戻り?をチェ?します?
199 * @og.rev 5.1.2.0 (2010/01/01) 置換するかど?を指定可能にする(isChange)属?追?
200 * @og.rev 5.7.2.2 (2014/01/24) エラー時に??タも?力します?
201 *
202 * @param data オリジナルのLineModel
203 *
204 * @return 処?換後?LineModel
205 */
206 public LineModel action( final LineModel data ) {
207 inCount++ ;
208 final FileLineModel fileData ;
209 if( data instanceof FileLineModel ) {
210 fileData = (FileLineModel)data ;
211 }
212 else {
213 String errMsg = "??タ?FileLineModel オブジェクトではありません? + CR ;
214 throw new RuntimeException( errMsg );
215 }
216
217
218 File org = fileData.getFile() ;
219 String orgName = org.getPath();
220 if( ! org.isFile() ) { return data; }
221
222 if( debug ) { println( "File:" + org ); } // 5.1.2.0 (2010/01/01) display の条件変更
223
224 BufferedReader reader = FileUtil.getBufferedReader( org,inEncode );
225 // File tempFile = new File( org.getPath() + "_temp" );
226 // PrintWriter tempWrt = FileUtil.getPrintWriter( tempFile,outEncode );
227 File tempFile = null;
228 PrintWriter tempWrt = null;
229
230 // 5.1.2.0 (2010/01/01) 置換する?合?前??
231 if( isChange ) {
232 tempFile = new File( orgName + "_temp" );
233 tempWrt = FileUtil.getPrintWriter( tempFile,outEncode );
234 }
235
236 boolean nextFlag = false;
237
238 try {
239 String line ;
240 int lineNo = 0;
241 while((line = reader.readLine()) != null) {
242 lineNo++ ;
243 StringBuilder buf = new StringBuilder( line );
244 // boolean foundFlag = false; // 行単位に初期化する?
245 for( int i=0; i<keyword.length; i++ ) {
246 int indx = buf.indexOf( keyword[i] );
247 // 置換対象発見?行?力用に見つかれば、true にする?
248 if( indx >= 0 ) {
249 // foundFlag = true;
250 nextFlag = true; // ?度でも見つかれば、true にセ?
251 if( display ) { println( orgName + ":" + lineNo + ":" + keyword[i] + ":" + line ); }
252 }
253 // 置換対象が見つかっても?isChange=true でなければ、置換???行わな??
254 if( isChange ) {
255 while( indx >= 0 ) {
256 buf.replace( indx,indx+keyword[i].length(),change[i] );
257 indx = buf.indexOf( keyword[i],indx+change[i].length() );
258 // nextFlag = true; // キーワードが存在したファイル?
259 cngCount++ ;
260 findCount++ ;
261 }
262 }
263 }
264 // 5.1.2.0 (2010/01/01) 置換する?合?処?
265 if( isChange ) {
266 tempWrt.println( buf.toString() );
267 }
268 }
269 }
270 catch ( IOException ex ) {
271 String errMsg = "処?にエラーが発生しました?" + data.getRowNo() + "]件目" + CR
272 // + data.toString() ;
273 + "data=[" + data.dataLine() + "]" + CR ; // 5.7.2.2 (2014/01/24) エラー時に??タも?力します?
274 throw new RuntimeException( errMsg,ex );
275 }
276 finally {
277 Closer.ioClose( reader );
278 Closer.ioClose( tempWrt );
279 }
280
281 // 5.1.2.0 (2010/01/01) 置換する?合?処?
282 if( isChange ) {
283 if( nextFlag ) {
284 if( !org.delete() ) {
285 String errMsg = "??ファイルを削除できませんでした?" + org + "]" + CR
286 + "data=[" + data.dataLine() + "]" + CR ; // 5.7.2.2 (2014/01/24) エラー時に??タも?力します?
287 throw new RuntimeException( errMsg );
288 }
289 if( !tempFile.renameTo( org ) ) {
290 String errMsg = "??ファイルをリネ??きませんでした?" + tempFile + "]" + CR
291 + "data=[" + data.dataLine() + "]" + CR ; // 5.7.2.2 (2014/01/24) エラー時に??タも?力します?
292 throw new RuntimeException( errMsg );
293 }
294 }
295 else {
296 if( !tempFile.delete() ) {
297 String errMsg = "??ファイルを削除できませんでした?" + tempFile + "]" + CR
298 + "data=[" + data.dataLine() + "]" + CR ; // 5.7.2.2 (2014/01/24) エラー時に??タも?力します?
299 throw new RuntimeException( errMsg );
300 }
301 }
302 }
303
304 return (nextFlag) ? data : null ;
305 }
306
307 /**
308 * プロセスの処?果のレポ?ト表現を返します?
309 * 処??ログラ?、?力件数、?力件数などの??です?
310 * こ???をそのまま、標準?力に出すことで、結果レポ?トと出来るよ?
311 * 形式で出してください?
312 *
313 * @return 処?果のレポ??
314 */
315 public String report() {
316 String report = "[" + getClass().getName() + "]" + CR
317 + TAB + "Search File Count : " + inCount + CR
318 + TAB + "Key Find Count : " + findCount + CR
319 + TAB + "Key Change Count : " + cngCount ;
320
321 return report ;
322 }
323
324 /**
325 * こ?クラスの使用方法を返します?
326 *
327 * @return こ?クラスの使用方?
328 */
329 public String usage() {
330 StringBuilder buf = new StringBuilder();
331
332 buf.append( "Process_GrepChange は、上流から受け取っ?FileLineModelから、語句? ).append( CR );
333 buf.append( "置換する?ChainProcess インターフェースの実?ラスです?" ).append( CR );
334 buf.append( "Process_Grep との違いは、チェ?するファイルのコピ??キーワードが存在" ).append( CR );
335 buf.append( "しなくと?作?することと、検索キーに正規表現が使えな???行置き換えが" ).append( CR );
336 buf.append( "出来な?とです?" ).append( CR );
337 buf.append( CR );
338 buf.append( "keywordFile より、置換する語句を含?ーと値のペアー(タブ区?)を読取り? ).append( CR );
339 buf.append( "対象とする語句を置換します?" ).append( CR );
340 buf.append( "keywordFile に、タブが含まれな?や、?頭にタブが存在して?場合?? ).append( CR );
341 buf.append( "そ?行を読み飛?します?また?区?タブ?何?存在しても構いません? ).append( CR );
342 buf.append( "ただし?タブで区?た前(キー)と後ろ(値)は、trim() されます?で、スペ?ス" ).append( CR );
343 buf.append( "が前後に存在して?場合?、ご注意く???" ).append( CR );
344 buf.append( "置換文?値)は、\t と \n の特殊文字が使用できます?" ).append( CR );
345 buf.append( "こ? GrepChange では、語句に、正規表現は使用できません。正規表現のキーワー? ).append( CR );
346 buf.append( "?字?を?行???と置き換える場合?、Process_Grep を使用して下さ??" ).append( CR );
347 buf.append( "こ?プログラ?は、上流から受け取っ?FileLineModel のファイルに対して? ).append( CR );
348 buf.append( "置き換えた結果も?同じファイルにセーブします?" ).append( CR );
349 buf.append( "??ファイルを保存したい場合?、予めバックア??を取得しておいてください? ).append( CR );
350 buf.append( "-inEncode は、?力ファイルのエンコード指定になります?" ).append( CR );
351 buf.append( "-outEncode は、?力ファイルのエンコードや、キーワードファイルのエンコー? ).append( CR );
352 buf.append( "?になります?(keywordFile は、? 出力ファイルと同じエンコードです?)" ).append( CR );
353 buf.append( "これら?エンコードが無??場合?、System.getProperty(\"file.encoding\") " ).append( CR );
354 buf.append( "で求まる?を使用します?" ).append( CR );
355 buf.append( CR );
356 buf.append( "上流?ロセスでは、Name 属?として、?File』を持ち、?は、Fileオブジェク? ).append( CR );
357 buf.append( "である、Process_FileSearch を使用するのが?便利です?それ以外?クラス? ).append( CR );
358 buf.append( "使用する場合でも?Name属?と、File オブジェクトを持つ LineModel を受け渡? ).append( CR );
359 buf.append( "できれば、使用可能です?" ).append( CR );
360 buf.append( CR );
361 buf.append( "引数??中に空白を含??合?、ダブルコー??ション(\"\") で括って下さ??" ).append( CR );
362 buf.append( "引数??の ?』?前後には、空白は挟めません。??key=value の様に" ).append( CR );
363 buf.append( "繋げてください? ).append( CR );
364 buf.append( CR ).append( CR );
365
366 buf.append( getArgument().usage() ).append( CR );
367
368 return buf.toString();
369 }
370
371 /**
372 * こ?クラスは、main メソ?から実行できません?
373 *
374 * @param args コマンド引数配?
375 */
376 public static void main( final String[] args ) {
377 LogWriter.log( new Process_GrepChange().usage() );
378 }
379 }