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 }