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 146 FileString fs = new FileString(); 147 fs.setFilename( keywordFile ); 148 fs.setEncode( inEncode ); 149 String[] lines = fs.getValue( "\n" ); 150 int len = lines.length; 151 if( len == 0 ) { 152 String errMsg = "keywordFile の??読み取れませんでした?" + keywordFile + "]" ; 153 throw new RuntimeException( errMsg ); 154 } 155 156 println( "keywordFile を?" + len + "件読み取りました? ); 157 List<String> keyList = new ArrayList<String>( len ); 158 List<String> cngList = new ArrayList<String>( len ); 159 160 for( int i=0; i<len; i++ ) { 161 // String line = lines[i].trim(); 162 String line = lines[i]; 163 int indx = line.indexOf( '\t' ); 164 if( indx <= 0 ) { continue ; } // TAB が?頭??存在しな??読み飛?す? 165 keyList.add( line.substring( 0,indx ).trim() ); 166 String cng = line.substring( indx+1 ).trim(); 167 cng = StringUtil.replace( cng,"\\n",CR ); 168 cng = StringUtil.replace( cng,"\\t","\t" ); 169 cngList.add( cng ); 170 } 171 keyword = keyList.toArray( new String[keyList.size()] ); 172 change = cngList.toArray( new String[cngList.size()] ); 173 } 174 175 /** 176 * プロセスの終?行います??に??、呼び出されます? 177 * 終???ファイルクローズ??クローズ?に使用します? 178 * 179 * @param isOK ト?タルで、OK?たかど?[true:成功/false:失敗] 180 */ 181 public void end( final boolean isOK ) { 182 // ここでは処?行いません? 183 } 184 185 /** 186 * 引数の LineModel を??るメソ?です? 187 * 変換処?? LineModel を返します? 188 * 後続??行わな?????タのフィルタリングを行う場?は? 189 * null ??タを返します?つまり?null ??タは、後続??行わな? 190 * フラグの代わりにも使用して?す? 191 * なお?変換処?? LineModel と、オリジナルの LineModel が? 192 * 同?、コピ?(クローン)か?、各処?ソ??決めて?す? 193 * ドキュメントに明記されて???合?、副作用が問題になる?合?? 194 * ???とに自?コピ?(クローン)して下さ?? 195 * 196 * @og.rev 5.7.2.2 (2014/01/24) エラー時に??タも?力します? 197 * 198 * @param data オリジナルのLineModel 199 * 200 * @return 処?換後?LineModel 201 */ 202 public LineModel action( final LineModel data ) { 203 inCount++ ; 204 final FileLineModel fileData ; 205 if( data instanceof FileLineModel ) { 206 fileData = (FileLineModel)data ; 207 } 208 else { 209 String errMsg = "??タ?FileLineModel オブジェクトではありません? + CR ; 210 throw new RuntimeException( errMsg ); 211 } 212 213 File org = fileData.getFile() ; 214 if( ! org.isFile() ) { return data; } 215 216 boolean nextFlag = false; 217 218 FileInputStream in = null; 219 Workbook wb = null; 220 Sheet sheet = null; 221 int stNo = -1 , rowNo = -1 , cellNo = -1 ; // エラー発生時に場?特定する為の?? 222 String sheetName = null; // エラー発生時に場?特定する為の?? 223 try { 224 in = new FileInputStream(org); 225 wb = WorkbookFactory.create(in); // HSSFとXSSFの違いをPOIが吸収してくれ? 226 227 for( stNo=0; stNo<wb.getNumberOfSheets(); stNo++ ) { 228 sheet = wb.getSheetAt(stNo); 229 sheetName = sheet.getSheetName(); 230 if( display ) { println( org.getPath() + ":" + sheetName ); } 231 232 int nFirstRow = sheet.getFirstRowNum(); 233 int nLastRow = sheet.getLastRowNum(); 234 for( rowNo = nFirstRow; rowNo <= nLastRow; rowNo++) { 235 Row oRow = sheet.getRow(rowNo); 236 if( oRow == null ) { continue; } 237 int nFirstCell = oRow.getFirstCellNum(); 238 int nLastCell = oRow.getLastCellNum(); 239 for( cellNo = nFirstCell; cellNo <= nLastCell; cellNo++) { 240 Cell oCell = oRow.getCell( cellNo ); 241 if( oCell != null ) { 242 int nCellType = oCell.getCellType(); 243 // switch(nCellType) { 244 // case Cell.CELL_TYPE_STRING: 245 if( nCellType == Cell.CELL_TYPE_STRING ) { 246 RichTextString richText = oCell.getRichStringCellValue(); 247 if( richText != null ) { 248 String orgText = richText.getString(); 249 if( debug ) { println( "DEBUG: [" + rowNo + "," + cellNo + "]=" + orgText ); } 250 251 String strText = changeString( orgText ); // ??変換。無変換の場合?、null が返る? 252 if( strText != null ) { 253 if( display ) { println( "CHANGE: [" + rowNo + "," + cellNo + "]=" + orgText + "? + strText ); } 254 oCell.setCellValue( strText ); // Cell に書き戻?RichTextStringでな?大丈夫?? 255 nextFlag = true; 256 findCount++; // 5.5.2.4 (2012/05/16) 257 } 258 } 259 // break; 260 // default : 261 // break; 262 } 263 } 264 } 265 } 266 267 // シート名も変換対象とする? 268 String newSheetName = changeString( sheetName ); // 無変換の場合?、null が返る? 269 if( newSheetName != null ) { 270 if( display ) { println( " sheetName=" + sheetName + "? + newSheetName ); } 271 wb.setSheetName(stNo, newSheetName); 272 nextFlag = true; 273 findCount++; // 5.5.2.4 (2012/05/16) 274 } 275 } 276 } 277 catch ( IOException ex ) { 278 String errMsg = "処?にエラーが発生しました?" + data.getRowNo() + "]件目" + CR 279 + org.toString() + CR 280 + "Sheet=[" + sheetName + "],SheetNo=[" + stNo + "],rowNo=[" + rowNo + "],cellNo=[" + cellNo + "]" + CR 281 + "data=[" + data.dataLine() + "]" + CR ; // 5.7.2.2 (2014/01/24) エラー時に??タも?力します? 282 throw new RuntimeException( errMsg,ex ); 283 } 284 catch ( InvalidFormatException ex ) { 285 String errMsg = "読み込みファイルの形式エラーが発生しました?" + data.getRowNo() + "]件目" + CR 286 + org.toString() + CR 287 + "Sheet=[" + sheetName + "],SheetNo=[" + stNo + "],rowNo=[" + rowNo + "],cellNo=[" + cellNo + "]" + CR 288 + "data=[" + data.dataLine() + "]" + CR ; // 5.7.2.2 (2014/01/24) エラー時に??タも?力します? 289 throw new RuntimeException( errMsg,ex ); 290 } 291 finally { 292 Closer.ioClose( in ); 293 } 294 295 if( isChange && nextFlag ) { 296 FileOutputStream fileOut = null ; 297 try { 298 fileOut = new FileOutputStream( org ); 299 wb.write(fileOut); 300 cngCount = findCount ; // 5.5.2.4 (2012/05/16) 置換時には、findCount を?cngCount にセ?しておく? 301 } 302 catch( IOException ex ) { 303 String errMsg = "ファイルへ書込み中にエラーが発生しました?" + data.getRowNo() + "]件目" + CR 304 + org.toString() + CR 305 + "data=[" + data.dataLine() + "]" + CR ; // 5.7.2.2 (2014/01/24) エラー時に??タも?力します? 306 throw new RuntimeException( errMsg,ex ); 307 } 308 finally { 309 Closer.ioClose( fileOut ); 310 } 311 } 312 313 return (nextFlag) ? data : null ; 314 } 315 316 /** 317 * 引数の??から、keyword ファイルを?に??変換を行います? 318 * 319 * ここでは、変換が行われたかど?を判定するため?変換された?? 320 * のみ、?を返します?変換されな??合?、null を返します?で? 321 * ご注意く??? 322 * 323 * @param org 変換前??? 324 * 325 * @return 変換後???(変換がなければ、null を返します?) 326 */ 327 public String changeString( final String org ) { 328 if( org == null || org.isEmpty() ) { return null; } 329 330 String tgt = org; 331 for( int i=0; i<keyword.length; i++ ) { 332 tgt = tgt.replaceAll( keyword[i],change[i] ); 333 } 334 335 // ?同じ場合?、null を返します? 336 if( org.equals( tgt ) || (ignoreCase && org.equalsIgnoreCase( tgt )) ) { 337 tgt = null; 338 } 339 340 return tgt ; 341 } 342 343 /** 344 * プロセスの処?果のレポ?ト表現を返します? 345 * 処??ログラ?、?力件数、?力件数などの??です? 346 * こ???をそのまま、標準?力に出すことで、結果レポ?トと出来るよ? 347 * 形式で出してください? 348 * 349 * @return 処?果のレポ?? 350 */ 351 public String report() { 352 String report = "[" + getClass().getName() + "]" + CR 353 + TAB + "Search File Count : " + inCount + CR 354 + TAB + "Key Find Count : " + findCount + CR 355 + TAB + "Key Change Count : " + cngCount ; 356 357 return report ; 358 } 359 360 /** 361 * こ?クラスの使用方法を返します? 362 * 363 * @return こ?クラスの使用方? 364 */ 365 public String usage() { 366 StringBuilder buf = new StringBuilder(); 367 368 buf.append( "Process_GrepChangeExcel は、上流から受け取っ?FileLineModelから、語句? ).append( CR ); 369 buf.append( "置換する?ChainProcess インターフェースの実?ラスです?" ).append( CR ); 370 buf.append( "Process_GrepChange との違いは、?力?のファイルが??ストファイルなのか?" ).append( CR ); 371 buf.append( "ネイ?ブEXCELファイルなのか?違いです?" ).append( CR ); 372 buf.append( CR ); 373 buf.append( "keywordFile より、置換する語句を含?ーと値のペアー(タブ区?)を読取り? ).append( CR ); 374 buf.append( "対象とする語句を置換します?" ).append( CR ); 375 buf.append( "keywordFile に、タブが含まれな?や、?頭にタブが存在して?場合?? ).append( CR ); 376 buf.append( "そ?行を読み飛?します?また?区?タブ?何?存在しても構いません? ).append( CR ); 377 buf.append( "ただし?タブで区?た前(キー)と後ろ(値)は、trim() されます?で、スペ?ス" ).append( CR ); 378 buf.append( "が前後に存在して?場合?、ご注意く???" ).append( CR ); 379 buf.append( "置換文?値)は、\t と \n の特殊文字が使用できます?" ).append( CR ); 380 buf.append( "こ? GrepChangeExcel では、語句に、正規表現は使用できません。正規表現のキーワー? ).append( CR ); 381 buf.append( "?字?を?行???と置き換える場合?、Process_Grep を使用して下さ??" ).append( CR ); 382 buf.append( "こ?プログラ?は、上流から受け取っ?FileLineModel のファイルに対して? ).append( CR ); 383 buf.append( "置き換えた結果も?同じファイルにセーブします?" ).append( CR ); 384 buf.append( "??ファイルを保存したい場合?、予めバックア??を取得しておいてください? ).append( CR ); 385 buf.append( "-inEncode は、keywordFileのエンコード指定になります?" ).append( CR ); 386 buf.append( "初期値は、互換性を持つため、System.getProperty(\"file.encoding\") ですが? ).append( CR ); 387 buf.append( "明示? UTF-8 などを指定して統?ておいたほ?良?しょ??" ).append( CR ); 388 buf.append( CR ); 389 buf.append( "上流?ロセスでは、Name 属?として、?File』を持ち、?は、Fileオブジェク? ).append( CR ); 390 buf.append( "である、Process_FileSearch を使用するのが?便利です?それ以外?クラス? ).append( CR ); 391 buf.append( "使用する場合でも?Name属?と、File オブジェクトを持つ LineModel を受け渡? ).append( CR ); 392 buf.append( "できれば、使用可能です?" ).append( CR ); 393 buf.append( CR ); 394 buf.append( "引数??中に空白を含??合?、ダブルコー??ション(\"\") で括って下さ??" ).append( CR ); 395 buf.append( "引数??の ?』?前後には、空白は挟めません。??key=value の様に" ).append( CR ); 396 buf.append( "繋げてください? ).append( CR ); 397 buf.append( CR ).append( CR ); 398 399 buf.append( getArgument().usage() ).append( CR ); 400 401 return buf.toString(); 402 } 403 404 /** 405 * こ?クラスは、main メソ?から実行できません? 406 * 407 * @param args コマンド引数配? 408 */ 409 public static void main( final String[] args ) { 410 LogWriter.log( new Process_GrepChangeExcel().usage() ); 411 } 412 }