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 *
079 * @version 4.0
080 * @author Kazuhiko Hasegawa
081 * @since JDK5.0,
082 */
083 public class Process_GrepChange extends AbstractProcess implements ChainProcess {
084 private String[] keyword = null;
085 private String[] change = null;
086 private boolean ignoreCase = false;
087 private boolean isChange = true; // 5.1.2.0 (2010/01/01) 置換するかどã�?�‹を指定可能にする
088 private String inEncode = null;
089 private String outEncode = null;
090 private boolean display = false; // 表示しなã�?
091
092 private int inCount = 0;
093 private int findCount = 0;
094 private int cngCount = 0;
095
096 private static final Map<String,String> mustProparty ; // ?»プロパティ?½å¿??チェãƒ?‚¯用 Map
097 private static final Map<String,String> usableProparty ; // ?»プロパティ?½整合æ?チェãƒ?‚¯ Map
098
099 static {
100 mustProparty = new LinkedHashMap<String,String>();
101 mustProparty.put( "keywordFile", "置換する語句を含ã‚?‚ーと値のペアー(タブ区åˆ?‚Š)(å¿??)" );
102
103 usableProparty = new LinkedHashMap<String,String>();
104 usableProparty.put( "ignoreCase", "検索時に大æ–?—小文字を区別しなã�?true)かどã�?�‹ã€? +
105 CR + "(初期値:区別する[false])" );
106 usableProparty.put( "isChange", "置換å?ç�?‚’実施する(true)かどã�?�‹" +
107 CR + "(初期値:置換する[true])" );
108 usableProparty.put( "inEncode", "入力ファイルのエンコードタイãƒ? );
109 usableProparty.put( "outEncode", "出力ファイルã‚?‚ーワードファイルのエンコードタイãƒ? );
110 usableProparty.put( "display", "結果を標準å?力に表示する(true)かしなã�?false)ã�? +
111 CR + "(初期値:false:表示しなã�?" );
112 }
113
114 /**
115 * ãƒ?ƒ•ォルトコンストラクターã€?
116 * こã?クラスは、動çš?½œæ?されますã?ãƒ?ƒ•ォルトコンストラクターでã€?
117 * super クラスに対して、å¿?¦�な初期化を行っておきますã?
118 *
119 */
120 public Process_GrepChange() {
121 super( "org.opengion.fukurou.process.Process_GrepChange",mustProparty,usableProparty );
122 }
123
124 /**
125 * プロセスの初期化を行いますã?初めにä¸?º¦ã�?�‘、呼び出されますã?
126 * 初期処ç�?ファイルオープンã€?¼¤?¢オープンç?に使用しますã?
127 *
128 * @og.rev 5.1.2.0 (2010/01/01) 置換するかどã�?�‹を指定可能にする(isChange)属æ?追åŠ?
129 *
130 * @param paramProcess ãƒ??タベã?スの接続å?æƒ??などを持ってã�?‚‹オブジェクãƒ?
131 */
132 public void init( final ParamProcess paramProcess ) {
133 Argument arg = getArgument();
134
135 String keywordFile = arg.getProparty("keywordFile" );
136 ignoreCase = arg.getProparty("ignoreCase",ignoreCase);
137 isChange = arg.getProparty("isChange",isChange); // 5.1.2.0 (2010/01/01)
138 inEncode = arg.getProparty("inEncode",System.getProperty("file.encoding"));
139 outEncode = arg.getProparty("outEncode",System.getProperty("file.encoding"));
140 display = arg.getProparty("display",display);
141
142 FileString fs = new FileString();
143 fs.setFilename( keywordFile );
144 fs.setEncode( outEncode );
145 String[] lines = fs.getValue( "\n" );
146 int len = lines.length;
147 if( len == 0 ) {
148 String errMsg = "keywordFile のå†?®¹ã�?読み取れませんでしたã€?" + keywordFile + "]" ;
149 throw new RuntimeException( errMsg );
150 }
151
152 println( "keywordFile をã?" + len + "件読み取りましたã€? );
153 List<String> keyList = new ArrayList<String>( len );
154 List<String> cngList = new ArrayList<String>( len );
155
156 for( int i=0; i<len; i++ ) {
157 // String line = lines[i].trim();
158 String line = lines[i];
159 int indx = line.indexOf( '\t' );
160 if( indx <= 0 ) { continue ; } // TAB がå?頭ã‚??存在しなã�?¡Œã?読み飛ã?すã?
161 keyList.add( line.substring( 0,indx ).trim() );
162 String cng = line.substring( indx+1 ).trim();
163 cng = StringUtil.replace( cng,"\\n",CR );
164 cng = StringUtil.replace( cng,"\\t","\t" );
165 cngList.add( cng );
166 }
167 keyword = keyList.toArray( new String[keyList.size()] );
168 change = cngList.toArray( new String[cngList.size()] );
169 }
170
171 /**
172 * プロセスの終äº?‚’行いますã?æœ?¾Œにä¸?º¦ã�?�‘、呼び出されますã?
173 * 終äº??ç�?ファイルクローズã€?¼¤?¢クローズç?に使用しますã?
174 *
175 * @param isOK トã?タルで、OKã�?�£たかどã�?�‹[true:成功/false:失敗]
176 */
177 public void end( final boolean isOK ) {
178 // ここでは処ç�?‚’行いませんã€?
179 }
180
181 /**
182 * 引数の LineModel をå?ç�?�™るメソãƒ?ƒ‰ですã?
183 * 変換処ç�?¾Œã? LineModel を返しますã?
184 * 後続å?ç�?‚’行わなã�??å�?ãƒ??タのフィルタリングを行う場å�?はã€?
185 * null ãƒ??タを返しますã?つまりã?null ãƒ??タは、後続å?ç�?‚’行わなã�?
186 * フラグの代わりにも使用してã�?�¾すã?
187 * なおã?変換処ç�?¾Œã? LineModel と、オリジナルの LineModel がã?
188 * 同ä¸?�‹、コピã?(クローン)かã?、各処ç�?ƒ¡ソãƒ?ƒ‰å†?�§決めてã�?�¾すã?
189 * ドキュメントに明記されてã�?�ªã�??合ã?、副作用が問題になるå?合ã?ã€?
190 * å�??ç�?�”とに自åˆ?�§コピã?(クローン)して下さã�??
191 *
192 * @og.rev 4.0.0.0 (2007/11/28) メソãƒ?ƒ‰の戻りå?をチェãƒ?‚¯しますã?
193 * @og.rev 5.1.2.0 (2010/01/01) 置換するかどã�?�‹を指定可能にする(isChange)属æ?追åŠ?
194 *
195 * @param data オリジナルのLineModel
196 *
197 * @return 処ç�?¤‰換後ã?LineModel
198 */
199 public LineModel action( final LineModel data ) {
200 inCount++ ;
201 final FileLineModel fileData ;
202 if( data instanceof FileLineModel ) {
203 fileData = (FileLineModel)data ;
204 }
205 else {
206 String errMsg = "ãƒ??タã�?FileLineModel オブジェクトではありませんã€? + CR ;
207 throw new RuntimeException( errMsg );
208 }
209
210 File org = fileData.getFile() ;
211 String orgName = org.getPath();
212 if( ! org.isFile() ) { return data; }
213
214 BufferedReader reader = FileUtil.getBufferedReader( org,inEncode );
215 // File tempFile = new File( org.getPath() + "_temp" );
216 // PrintWriter tempWrt = FileUtil.getPrintWriter( tempFile,outEncode );
217 File tempFile = null;
218 PrintWriter tempWrt = null;
219
220 // 5.1.2.0 (2010/01/01) 置換するå?合ã?前å?ç�?
221 if( isChange ) {
222 tempFile = new File( orgName + "_temp" );
223 tempWrt = FileUtil.getPrintWriter( tempFile,outEncode );
224 }
225
226 boolean nextFlag = false;
227
228 try {
229 String line ;
230 int lineNo = 0;
231 while((line = reader.readLine()) != null) {
232 lineNo++ ;
233 StringBuilder buf = new StringBuilder( line );
234 // boolean foundFlag = false; // 行単位に初期化するã?
235 for( int i=0; i<keyword.length; i++ ) {
236 int indx = buf.indexOf( keyword[i] );
237 // 置換対象発見ã?行å?力用に見つかれば、true にするã€?
238 if( indx >= 0 ) {
239 // foundFlag = true;
240 nextFlag = true; // ?‘度でも見つかれば、true にセãƒ?ƒˆ
241 if( display ) { println( orgName + ":" + lineNo + ":" + keyword[i] + ":" + line ); }
242 }
243 // 置換対象が見つかってもã?isChange=true でなければ、置換å?ç�??行わなã�??
244 if( isChange ) {
245 while( indx >= 0 ) {
246 buf.replace( indx,indx+keyword[i].length(),change[i] );
247 indx = buf.indexOf( keyword[i],indx+change[i].length() );
248 // nextFlag = true; // キーワードが存在したファイルã€?
249 cngCount++ ;
250 findCount++ ;
251 }
252 }
253 }
254 // 5.1.2.0 (2010/01/01) 置換するå?合ã?処ç�?
255 if( isChange ) {
256 tempWrt.println( buf.toString() );
257 }
258 }
259 }
260 catch ( IOException ex ) {
261 String errMsg = "処ç�?¸にエラーが発生しましたã€?" + data.getRowNo() + "]件目" + CR
262 + data.toString() ;
263 throw new RuntimeException( errMsg,ex );
264 }
265 finally {
266 Closer.ioClose( reader );
267 Closer.ioClose( tempWrt );
268 }
269
270 // 5.1.2.0 (2010/01/01) 置換するå?合ã?処ç�?
271 if( isChange ) {
272 if( nextFlag ) {
273 if( !org.delete() ) {
274 String errMsg = "æ‰?®šã?ファイルを削除できませんでしたã€?" + org + "]" ;
275 throw new RuntimeException( errMsg );
276 }
277 if( !tempFile.renameTo( org ) ) {
278 String errMsg = "æ‰?®šã?ファイルをリネã?ãƒ?�§きませんでしたã€?" + tempFile + "]" ;
279 throw new RuntimeException( errMsg );
280 }
281 }
282 else {
283 if( !tempFile.delete() ) {
284 String errMsg = "æ‰?®šã?ファイルを削除できませんでしたã€?" + tempFile + "]" ;
285 throw new RuntimeException( errMsg );
286 }
287 }
288 }
289
290 return (nextFlag) ? data : null ;
291 }
292
293 /**
294 * プロセスの処ç�?µ�果のレポã?ト表現を返しますã?
295 * 処ç�??ログラãƒ?��、å?力件数、å?力件数などのæƒ??ですã?
296 * こã?æ–?—å?をそのまま、標準å?力に出すことで、結果レポã?トと出来るよã�?�ª
297 * 形式で出してくださいã€?
298 *
299 * @return 処ç�?µ�果のレポã?ãƒ?
300 */
301 public String report() {
302 String report = "[" + getClass().getName() + "]" + CR
303 + TAB + "Search File Count : " + inCount + CR
304 + TAB + "Key Find Count : " + findCount + CR
305 + TAB + "Key Change Count : " + cngCount ;
306
307 return report ;
308 }
309
310 /**
311 * こã?クラスの使用方法を返しますã?
312 *
313 * @return こã?クラスの使用方æ³?
314 */
315 public String usage() {
316 StringBuilder buf = new StringBuilder();
317
318 buf.append( "Process_GrepChange は、上流から受け取っã�?FileLineModelから、語句ã‚? ).append( CR );
319 buf.append( "置換するã?ChainProcess インターフェースの実è£?‚¯ラスですã?" ).append( CR );
320 buf.append( "Process_Grep との違いは、チェãƒ?‚¯するファイルのコピã?ã‚?キーワードが存在" ).append( CR );
321 buf.append( "しなくとã‚?作æ?することと、検索キーに正規表現が使えなã�??è¤?•°行置き換えが" ).append( CR );
322 buf.append( "出来なã�?�“とですã?" ).append( CR );
323 buf.append( CR );
324 buf.append( "keywordFile より、置換する語句を含ã‚?‚ーと値のペアー(タブ区åˆ?‚Š)を読取りã€? ).append( CR );
325 buf.append( "対象とする語句を置換しますã?" ).append( CR );
326 buf.append( "keywordFile に、タブが含まれなã�?¡Œや、å?頭にタブが存在してã�?‚‹場合ã?ã€? ).append( CR );
327 buf.append( "そã?行を読み飛ã?しますã?またã?区åˆ?‚Šタブã?何å?存在しても構いませんã€? ).append( CR );
328 buf.append( "ただしã?タブで区åˆ?�£た前(キー)と後ろ(値)は、trim() されますã?で、スペã?ス" ).append( CR );
329 buf.append( "が前後に存在してã�?‚‹場合ã?、ご注意くã�?�•ã�??" ).append( CR );
330 buf.append( "置換文å?値)は、\t と \n の特殊文字が使用できますã?" ).append( CR );
331 buf.append( "こã? GrepChange では、語句に、正規表現は使用できません。正規表現のキーワーãƒ? ).append( CR );
332 buf.append( "ã‚?–‡字å?をè¤?•°行ã?æ–?—å?と置き換える場合ã?、Process_Grep を使用して下さã�??" ).append( CR );
333 buf.append( "こã?プログラãƒ?�§は、上流から受け取っã�?FileLineModel のファイルに対してã€? ).append( CR );
334 buf.append( "置き換えた結果もã?同じファイルにセーブしますã?" ).append( CR );
335 buf.append( "å…??ファイルを保存したい場合ã?、予めバックアãƒ??を取得しておいてくださいã€? ).append( CR );
336 buf.append( "-inEncode は、å?力ファイルのエンコード指定になりますã?" ).append( CR );
337 buf.append( "-outEncode は、å?力ファイルのエンコードや、キーワードファイルのエンコーãƒ? ).append( CR );
338 buf.append( "æŒ?®šになりますã?(keywordFile は、å¿?�š 出力ファイルと同じエンコードですã?)" ).append( CR );
339 buf.append( "これらã?エンコードが無æŒ?®šã?場合ã?、System.getProperty(\"file.encoding\") " ).append( CR );
340 buf.append( "で求まるå?を使用しますã?" ).append( CR );
341 buf.append( CR );
342 buf.append( "上流ã?ロセスでは、Name 属æ?として、ã?File』を持ち、å?は、Fileオブジェクãƒ? ).append( CR );
343 buf.append( "である、Process_FileSearch を使用するのがã?便利ですã?それ以外ã?クラスã‚? ).append( CR );
344 buf.append( "使用する場合でもã?Name属æ?と、File オブジェクトを持つ LineModel を受け渡ã�? ).append( CR );
345 buf.append( "できれば、使用可能ですã?" ).append( CR );
346 buf.append( CR );
347 buf.append( "引数æ–?—å?中に空白を含ã‚??合ã?、ダブルコーãƒ??ション(\"\") で括って下さã�??" ).append( CR );
348 buf.append( "引数æ–?—å?の ã€?』ã?前後には、空白は挟めません。å¿?�šã€?key=value の様に" ).append( CR );
349 buf.append( "繋げてくださいã€? ).append( CR );
350 buf.append( CR ).append( CR );
351
352 buf.append( getArgument().usage() ).append( CR );
353
354 return buf.toString();
355 }
356
357 /**
358 * こã?クラスは、main メソãƒ?ƒ‰から実行できませんã€?
359 *
360 * @param args コマンド引数配å?
361 */
362 public static void main( final String[] args ) {
363 LogWriter.log( new Process_GrepChange().usage() );
364 }
365 }