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.FileString;
020 import org.opengion.fukurou.util.Closer ;
021 import org.opengion.fukurou.util.StringUtil ;
022 import org.opengion.fukurou.util.LogWriter;
023
024 import org.apache.poi.ss.usermodel.Cell;
025 import org.apache.poi.ss.usermodel.RichTextString;
026 import org.apache.poi.ss.usermodel.Row;
027 import org.apache.poi.ss.usermodel.Sheet;
028 import org.apache.poi.ss.usermodel.Workbook;
029 import org.apache.poi.ss.usermodel.WorkbookFactory;
030 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
031
032 import java.util.Map ;
033 import java.util.LinkedHashMap ;
034 import java.util.List ;
035 import java.util.ArrayList ;
036
037 import java.io.File;
038 import java.io.FileInputStream;
039 import java.io.FileOutputStream;
040 import java.io.IOException;
041
042 /**
043 * Process_GrepChangeExcel は、上流から受け取っã�?FileLineModelから、語句ã‚?
044 * 置換するã?ChainProcess インターフェースの実è£?‚¯ラスですã?
045 *
046 * Process_GrepChange との違いは、å?力å?のファイルがã?ãƒ?‚ストファイルなのかã?
047 * ネイãƒ?‚£ブEXCELファイルなのかã?違いですã?
048 *
049 * keywordFile より、置換する語句を含ã‚?‚ーと値のペアー(タブ区åˆ?‚Š)を読取りã€?
050 * 対象とする語句をセル単位に置換しますã?
051 * keywordFile に、タブが含まれなã�?¡Œや、å?頭にタブが存在してã�?‚‹場合ã?ã€?
052 * そã?行を読み飛ã?しますã?またã?区åˆ?‚Šタブã?何å?存在しても構いませんã€?
053 * ただしã?タブで区åˆ?�£た前(キー)と後ろ(値)は、trim() されますã?で、スペã?ス
054 * が前後に存在してã�?‚‹場合ã?、ご注意くã�?�•ã�??
055 * 置換文å?値)は、\t と \n の特殊文字が使用できますã?
056 * こã? GrepChangeExcel では、語句に、正規表現は使用できません。正規表現のキーワーãƒ?
057 * ã‚?–‡字å?をè¤?•°行ã?æ–?—å?と置き換える場合ã?、Process_Grep を使用してくださいã€?
058 * こã?プログラãƒ?�§は、上流から受け取っã�?FileLineModel のファイルに対してã€?
059 * 置き換えた結果もã?同じファイルにセーブしますã?
060 * å…??ファイルを保存したい場合ã?、予めバックアãƒ??を取得しておいてくださいã€?
061 * -inEncode は、keywordFileのエンコード指定になりますã?
062 * 初期値は、互換性を持つため、System.getProperty("file.encoding") ですがã€?
063 * 明示çš?�« UTF-8 などを指定して統ä¸?�—ておいたほã�?�Œ良ã�?�§しょã�??
064 *
065 * 上流ã?ロセスでは、Name 属æ?として、ã?File』を持ち、å?は、Fileオブジェクãƒ?
066 * である、Process_FileSearch を使用するのがã?便利ですã?それ以外ã?クラスã‚?
067 * 使用する場合でもã?Name属æ?と、File オブジェクトを持つ LineModel を受け渡ã�?
068 * できれば、使用可能ですã?
069 *
070 * 引数æ–?—å?中にスペã?スを含ã‚??合ã?、ダブルコーãƒ??ション("") で括って下さã�??
071 * 引数æ–?—å?の ã€?』ã?前後には、スペã?スは挟めません。å¿?�šã€?key=value の様に
072 * 繋げてくださいã€?
073 *
074 * Process_GrepChangeExcel -keyword=検索æ–?—å? -ignoreCase=true -outfile=OUTFILE -encode=UTF-8
075 *
076 * -keywordFile=キーワーãƒ? ?š置換する語句を含ã‚?‚ーと値のペアー(タブ区åˆ?‚Š)
077 * [-ignoreCase=大æ–?—小文å?] ?š検索時に大æ–?—小文字を区別しなã�?true)かどã�?�‹(初期値:false[区別する])
078 * [-isChange=置換可否 ] ?š置換å?ç�?‚’実施する(true)かどã�?�‹(初期値:true[置換する])
079 * [-inEncode=入力エンコーãƒ?] ?škeywordFileのエンコーãƒ?
080 * [-display=[false/true] ] ?š結果を標準å?力に表示する(true)かしなã�?false)ã�?初期値:false[表示しない])
081 * [-debug=[false/true] ] ?šデバッグ用に実行å?容を表示するかどã�?�‹を指å®?初期値:false[表示しない])
082 *
083 * @og.rev 5.5.1.7 (2012/04/16) 新規追åŠ?
084 * @version 4.0
085 * @author Kazuhiko Hasegawa
086 * @since JDK5.0,
087 */
088 public class Process_GrepChangeExcel extends AbstractProcess implements ChainProcess {
089 private String[] keyword = null;
090 private String[] change = null;
091 private boolean ignoreCase = false;
092 private boolean isChange = true; // 5.1.2.0 (2010/01/01) 置換するかどã�?�‹を指定可能にする
093 // private String inEncode = null; // 5.5.2.4 (2012/05/16) ローカル変数åŒ?
094 private boolean display = false; // 表示しなã�?
095 private boolean debug = false; // 表示しなã�?
096
097 private int inCount = 0;
098 private int findCount = 0;
099 private int cngCount = 0;
100
101 private static final Map<String,String> mustProparty ; // ?»プロパティ?½å¿??チェãƒ?‚¯用 Map
102 private static final Map<String,String> usableProparty ; // ?»プロパティ?½整合æ?チェãƒ?‚¯ Map
103
104 static {
105 mustProparty = new LinkedHashMap<String,String>();
106 mustProparty.put( "keywordFile", "置換する語句を含ã‚?‚ーと値のペアー(タブ区åˆ?‚Š)(å¿??)" );
107
108 usableProparty = new LinkedHashMap<String,String>();
109 usableProparty.put( "ignoreCase", "検索時に大æ–?—小文字を区別しなã�?true)かどã�?�‹ã€? +
110 CR + "(初期値:区別する[false])" );
111 usableProparty.put( "isChange", "置換å?ç�?‚’実施する(true)かどã�?�‹" +
112 CR + "(初期値:置換する[true])" );
113 usableProparty.put( "inEncode", "keywordFileのエンコーãƒ? );
114 usableProparty.put( "display", "結果を標準å?力に表示する(true)かしなã�?false)ã�? +
115 CR + "(初期値:false:表示しなã�?" );
116 usableProparty.put( "debug", "ãƒ?ƒ�ãƒ?‚°用に実行å?容を表示するかどã�?�‹を指å®? +
117 CR + "(初期値:false:表示しなã�?" );
118 }
119
120 /**
121 * ãƒ?ƒ•ォルトコンストラクターã€?
122 * こã?クラスは、動çš?½œæ?されますã?ãƒ?ƒ•ォルトコンストラクターでã€?
123 * super クラスに対して、å¿?¦�な初期化を行っておきますã?
124 *
125 */
126 public Process_GrepChangeExcel() {
127 super( "org.opengion.fukurou.process.Process_GrepChangeExcel",mustProparty,usableProparty );
128 }
129
130 /**
131 * プロセスの初期化を行いますã?初めにä¸?º¦ã�?�‘、呼び出されますã?
132 * 初期処ç�?ファイルオープンã€?¼¤?¢オープンç?に使用しますã?
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 String inEncode = arg.getProparty("inEncode",System.getProperty("file.encoding"));
143 display = arg.getProparty("display",display);
144 debug = arg.getProparty("debug",debug);
145 // if( debug ) { println( arg.toString() ); } // 5.7.3.0 (2014/02/07) ãƒ?ƒ�ãƒ?‚°æƒ??
146
147 FileString fs = new FileString();
148 fs.setFilename( keywordFile );
149 fs.setEncode( inEncode );
150 String[] lines = fs.getValue( "\n" );
151 int len = lines.length;
152 if( len == 0 ) {
153 String errMsg = "keywordFile のå†?®¹ã�?読み取れませんでしたã€?" + keywordFile + "]" ;
154 throw new RuntimeException( errMsg );
155 }
156
157 println( "keywordFile をã?" + len + "件読み取りましたã€? );
158 List<String> keyList = new ArrayList<String>( len );
159 List<String> cngList = new ArrayList<String>( len );
160
161 for( int i=0; i<len; i++ ) {
162 // String line = lines[i].trim();
163 String line = lines[i];
164 int indx = line.indexOf( '\t' );
165 if( indx <= 0 ) { continue ; } // TAB がå?頭ã‚??存在しなã�?¡Œã?読み飛ã?すã?
166 keyList.add( line.substring( 0,indx ).trim() );
167 String cng = line.substring( indx+1 ).trim();
168 cng = StringUtil.replace( cng,"\\n",CR );
169 cng = StringUtil.replace( cng,"\\t","\t" );
170 cngList.add( cng );
171 }
172 keyword = keyList.toArray( new String[keyList.size()] );
173 change = cngList.toArray( new String[cngList.size()] );
174 }
175
176 /**
177 * プロセスの終äº?‚’行いますã?æœ?¾Œにä¸?º¦ã�?�‘、呼び出されますã?
178 * 終äº??ç�?ファイルクローズã€?¼¤?¢クローズç?に使用しますã?
179 *
180 * @param isOK トã?タルで、OKã�?�£たかどã�?�‹[true:成功/false:失敗]
181 */
182 public void end( final boolean isOK ) {
183 // ここでは処ç�?‚’行いませんã€?
184 }
185
186 /**
187 * 引数の LineModel をå?ç�?�™るメソãƒ?ƒ‰ですã?
188 * 変換処ç�?¾Œã? LineModel を返しますã?
189 * 後続å?ç�?‚’行わなã�??å�?ãƒ??タのフィルタリングを行う場å�?はã€?
190 * null ãƒ??タを返しますã?つまりã?null ãƒ??タは、後続å?ç�?‚’行わなã�?
191 * フラグの代わりにも使用してã�?�¾すã?
192 * なおã?変換処ç�?¾Œã? LineModel と、オリジナルの LineModel がã?
193 * 同ä¸?�‹、コピã?(クローン)かã?、各処ç�?ƒ¡ソãƒ?ƒ‰å†?�§決めてã�?�¾すã?
194 * ドキュメントに明記されてã�?�ªã�??合ã?、副作用が問題になるå?合ã?ã€?
195 * å�??ç�?�”とに自åˆ?�§コピã?(クローン)して下さã�??
196 *
197 * @og.rev 5.7.2.2 (2014/01/24) エラー時にãƒ??タもå?力しますã?
198 *
199 * @param data オリジナルのLineModel
200 *
201 * @return 処ç�?¤‰換後ã?LineModel
202 */
203 public LineModel action( final LineModel data ) {
204 inCount++ ;
205 final FileLineModel fileData ;
206 if( data instanceof FileLineModel ) {
207 fileData = (FileLineModel)data ;
208 }
209 else {
210 String errMsg = "ãƒ??タã�?FileLineModel オブジェクトではありませんã€? + CR ;
211 throw new RuntimeException( errMsg );
212 }
213
214 File org = fileData.getFile() ;
215 if( ! org.isFile() ) { return data; }
216
217 boolean nextFlag = false;
218
219 FileInputStream in = null;
220 Workbook wb = null;
221 Sheet sheet = null;
222 int stNo = -1 , rowNo = -1 , cellNo = -1 ; // エラー発生時に場æ‰?‚’特定する為のæƒ??
223 String sheetName = null; // エラー発生時に場æ‰?‚’特定する為のæƒ??
224 try {
225 in = new FileInputStream(org);
226 wb = WorkbookFactory.create(in); // HSSFとXSSFの違いをPOIが吸収してくれã‚?
227
228 for( stNo=0; stNo<wb.getNumberOfSheets(); stNo++ ) {
229 sheet = wb.getSheetAt(stNo);
230 sheetName = sheet.getSheetName();
231 if( display ) { println( org.getPath() + ":" + sheetName ); }
232
233 int nFirstRow = sheet.getFirstRowNum();
234 int nLastRow = sheet.getLastRowNum();
235 for( rowNo = nFirstRow; rowNo <= nLastRow; rowNo++) {
236 Row oRow = sheet.getRow(rowNo);
237 if( oRow == null ) { continue; }
238 int nFirstCell = oRow.getFirstCellNum();
239 int nLastCell = oRow.getLastCellNum();
240 for( cellNo = nFirstCell; cellNo <= nLastCell; cellNo++) {
241 Cell oCell = oRow.getCell( cellNo );
242 if( oCell != null ) {
243 int nCellType = oCell.getCellType();
244 // switch(nCellType) {
245 // case Cell.CELL_TYPE_STRING:
246 if( nCellType == Cell.CELL_TYPE_STRING ) {
247 RichTextString richText = oCell.getRichStringCellValue();
248 if( richText != null ) {
249 String orgText = richText.getString();
250 if( debug ) { println( "DEBUG: [" + rowNo + "," + cellNo + "]=" + orgText ); }
251
252 String strText = changeString( orgText ); // æ–?—å?変換。無変換の場合ã?、null が返るã€?
253 if( strText != null ) {
254 if( display ) { println( "CHANGE: [" + rowNo + "," + cellNo + "]=" + orgText + "� + strText ); }
255 oCell.setCellValue( strText ); // Cell に書き戻ã�?RichTextStringでなã�?�Œ大丈夫??
256 nextFlag = true;
257 findCount++; // 5.5.2.4 (2012/05/16)
258 }
259 }
260 // break;
261 // default :
262 // break;
263 }
264 }
265 }
266 }
267
268 // シート名も変換対象とするã€?
269 String newSheetName = changeString( sheetName ); // 無変換の場合ã?、null が返るã€?
270 if( newSheetName != null ) {
271 if( display ) { println( " sheetName=" + sheetName + "� + newSheetName ); }
272 wb.setSheetName(stNo, newSheetName);
273 nextFlag = true;
274 findCount++; // 5.5.2.4 (2012/05/16)
275 }
276 }
277 }
278 catch ( IOException ex ) {
279 String errMsg = "処ç�?¸にエラーが発生しましたã€?" + data.getRowNo() + "]件目" + CR
280 + org.toString() + CR
281 + "Sheet=[" + sheetName + "],SheetNo=[" + stNo + "],rowNo=[" + rowNo + "],cellNo=[" + cellNo + "]" + CR
282 + "data=[" + data.dataLine() + "]" + CR ; // 5.7.2.2 (2014/01/24) エラー時にãƒ??タもå?力しますã?
283 throw new RuntimeException( errMsg,ex );
284 }
285 catch ( InvalidFormatException ex ) {
286 String errMsg = "読み込みファイルの形式エラーが発生しましたã€?" + data.getRowNo() + "]件目" + CR
287 + org.toString() + CR
288 + "Sheet=[" + sheetName + "],SheetNo=[" + stNo + "],rowNo=[" + rowNo + "],cellNo=[" + cellNo + "]" + CR
289 + "data=[" + data.dataLine() + "]" + CR ; // 5.7.2.2 (2014/01/24) エラー時にãƒ??タもå?力しますã?
290 throw new RuntimeException( errMsg,ex );
291 }
292 finally {
293 Closer.ioClose( in );
294 }
295
296 if( isChange && nextFlag ) {
297 FileOutputStream fileOut = null ;
298 try {
299 fileOut = new FileOutputStream( org );
300 wb.write(fileOut);
301 cngCount = findCount ; // 5.5.2.4 (2012/05/16) 置換時には、findCount をã?cngCount にセãƒ?ƒˆしておくã€?
302 }
303 catch( IOException ex ) {
304 String errMsg = "ファイルへ書込み中にエラーが発生しましたã€?" + data.getRowNo() + "]件目" + CR
305 + org.toString() + CR
306 + "data=[" + data.dataLine() + "]" + CR ; // 5.7.2.2 (2014/01/24) エラー時にãƒ??タもå?力しますã?
307 throw new RuntimeException( errMsg,ex );
308 }
309 finally {
310 Closer.ioClose( fileOut );
311 }
312 }
313
314 return (nextFlag) ? data : null ;
315 }
316
317 /**
318 * 引数のæ–?—å?から、keyword ファイルをå?にæ–?—å?変換を行いますã?
319 *
320 * ここでは、変換が行われたかどã�?�‹を判定するためã?変換されたå?å�?
321 * のみ、å?を返しますã?変換されなã�??合ã?、null を返しますã?でã€?
322 * ご注意くã�?�•ã�??
323 *
324 * @param org 変換前ã?æ–?—å?
325 *
326 * @return 変換後ã?æ–?—å?(変換がなければ、null を返しますã?)
327 */
328 public String changeString( final String org ) {
329 if( org == null || org.isEmpty() ) { return null; }
330
331 String tgt = org;
332 for( int i=0; i<keyword.length; i++ ) {
333 tgt = tgt.replaceAll( keyword[i],change[i] );
334 }
335
336 // å…?�¨同じ場合ã?、null を返しますã?
337 if( org.equals( tgt ) || (ignoreCase && org.equalsIgnoreCase( tgt )) ) {
338 tgt = null;
339 }
340
341 return tgt ;
342 }
343
344 /**
345 * プロセスの処ç�?µ�果のレポã?ト表現を返しますã?
346 * 処ç�??ログラãƒ?��、å?力件数、å?力件数などのæƒ??ですã?
347 * こã?æ–?—å?をそのまま、標準å?力に出すことで、結果レポã?トと出来るよã�?�ª
348 * 形式で出してくださいã€?
349 *
350 * @return 処ç�?µ�果のレポã?ãƒ?
351 */
352 public String report() {
353 String report = "[" + getClass().getName() + "]" + CR
354 + TAB + "Search File Count : " + inCount + CR
355 + TAB + "Key Find Count : " + findCount + CR
356 + TAB + "Key Change Count : " + cngCount ;
357
358 return report ;
359 }
360
361 /**
362 * こã?クラスの使用方法を返しますã?
363 *
364 * @return こã?クラスの使用方æ³?
365 */
366 public String usage() {
367 StringBuilder buf = new StringBuilder();
368
369 buf.append( "Process_GrepChangeExcel は、上流から受け取っã�?FileLineModelから、語句ã‚? ).append( CR );
370 buf.append( "置換するã?ChainProcess インターフェースの実è£?‚¯ラスですã?" ).append( CR );
371 buf.append( "Process_GrepChange との違いは、å?力å?のファイルがã?ãƒ?‚ストファイルなのかã?" ).append( CR );
372 buf.append( "ネイãƒ?‚£ブEXCELファイルなのかã?違いですã?" ).append( CR );
373 buf.append( CR );
374 buf.append( "keywordFile より、置換する語句を含ã‚?‚ーと値のペアー(タブ区åˆ?‚Š)を読取りã€? ).append( CR );
375 buf.append( "対象とする語句を置換しますã?" ).append( CR );
376 buf.append( "keywordFile に、タブが含まれなã�?¡Œや、å?頭にタブが存在してã�?‚‹場合ã?ã€? ).append( CR );
377 buf.append( "そã?行を読み飛ã?しますã?またã?区åˆ?‚Šタブã?何å?存在しても構いませんã€? ).append( CR );
378 buf.append( "ただしã?タブで区åˆ?�£た前(キー)と後ろ(値)は、trim() されますã?で、スペã?ス" ).append( CR );
379 buf.append( "が前後に存在してã�?‚‹場合ã?、ご注意くã�?�•ã�??" ).append( CR );
380 buf.append( "置換文å?値)は、\t と \n の特殊文字が使用できますã?" ).append( CR );
381 buf.append( "こã? GrepChangeExcel では、語句に、正規表現は使用できません。正規表現のキーワーãƒ? ).append( CR );
382 buf.append( "ã‚?–‡字å?をè¤?•°行ã?æ–?—å?と置き換える場合ã?、Process_Grep を使用して下さã�??" ).append( CR );
383 buf.append( "こã?プログラãƒ?�§は、上流から受け取っã�?FileLineModel のファイルに対してã€? ).append( CR );
384 buf.append( "置き換えた結果もã?同じファイルにセーブしますã?" ).append( CR );
385 buf.append( "å…??ファイルを保存したい場合ã?、予めバックアãƒ??を取得しておいてくださいã€? ).append( CR );
386 buf.append( "-inEncode は、keywordFileのエンコード指定になりますã?" ).append( CR );
387 buf.append( "初期値は、互換性を持つため、System.getProperty(\"file.encoding\") ですがã€? ).append( CR );
388 buf.append( "明示çš?�« UTF-8 などを指定して統ä¸?�—ておいたほã�?�Œ良ã�?�§しょã�??" ).append( CR );
389 buf.append( CR );
390 buf.append( "上流ã?ロセスでは、Name 属æ?として、ã?File』を持ち、å?は、Fileオブジェクãƒ? ).append( CR );
391 buf.append( "である、Process_FileSearch を使用するのがã?便利ですã?それ以外ã?クラスã‚? ).append( CR );
392 buf.append( "使用する場合でもã?Name属æ?と、File オブジェクトを持つ LineModel を受け渡ã�? ).append( CR );
393 buf.append( "できれば、使用可能ですã?" ).append( CR );
394 buf.append( CR );
395 buf.append( "引数æ–?—å?中に空白を含ã‚??合ã?、ダブルコーãƒ??ション(\"\") で括って下さã�??" ).append( CR );
396 buf.append( "引数æ–?—å?の ã€?』ã?前後には、空白は挟めません。å¿?�šã€?key=value の様に" ).append( CR );
397 buf.append( "繋げてくださいã€? ).append( CR );
398 buf.append( CR ).append( CR );
399
400 buf.append( getArgument().usage() ).append( CR );
401
402 return buf.toString();
403 }
404
405 /**
406 * こã?クラスは、main メソãƒ?ƒ‰から実行できませんã€?
407 *
408 * @param args コマンド引数配å?
409 */
410 public static void main( final String[] args ) {
411 LogWriter.log( new Process_GrepChangeExcel().usage() );
412 }
413 }