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 */ 016package org.opengion.fukurou.util; 017 018import java.io.UnsupportedEncodingException; 019import java.util.List; 020import java.util.ArrayList; 021import java.util.Arrays; 022 023/** 024 * FixLengthData.java は、固定長データを作成するための簡易クラスです。 025 * 026 * データの項目(String[])を、それぞれの中で最大桁数にあわせて、スペース埋めします。 027 * 各項目間に、追加するスペース数は、setAddLength( int[] ) メソッドで、 028 * 各項目のタイプ(半角文字、全角混在、数字)の指定は、setType( int[] ) メソッド行います。 029 * 030 * このクラスは同期処理は保障されていません。 031 * 032 * @og.rev 5.6.6.0 (2013/07/05) keys の整合性チェックを追加 033 * 034 * @version 4.0 035 * @author Kazuhiko Hasegawa 036 * @since JDK5.0, 037 */ 038public final class FixLengthData { 039 040 /** 項目タイプの定義変数:X:半角文字 {@value} */ 041 public static final int X = 0 ; 042 /** 項目タイプの定義変数:S:数字(前空白) {@value} */ 043 public static final int S = 1 ; // 5.6.6.0 (2013/07/05) 前空白詰めに変更 044 /** 項目タイプの定義変数:K:半角全角混在 {@value} */ 045 public static final int K = 2 ; 046 /** 項目タイプの定義変数:X9:数字(前ゼロ) {@value} */ 047 public static final int S0 = 3 ; // 5.6.6.0 (2013/07/05) 前ゼロ詰めを変更 048 049 /** 項目間空白配列の定義変数:T:タブ区切り {@value} */ 050 public static final int T = -1 ; // 5.6.6.0 (2013/07/05) タブ区切り 051 public static final int T2 = -2 ; // 5.6.6.0 (2013/07/05) タブ区切り 052 public static final int T3 = -3 ; // 5.6.6.0 (2013/07/05) タブ区切り 053 public static final int T4 = -4 ; // 5.6.6.0 (2013/07/05) タブ区切り 054 055 private static final String CR = System.getProperty("line.separator"); 056 057 /** 初期 ENCODE 名 {@value} */ 058 public static final String ENCODE = "Windows-31J" ; 059 060 private final int[] addLen ; // 各データ間に追加するスペースを設定する。 061 private final int[] type ; // 各データの固定長形式。 0:半角文字 1:数字(前空白) 2:半角全角混在 3:数字(前ゼロ) 062 private final int size ; // データの個数 063 064 private int[] maxLen = null; // 内部変数。各データの最大長を記憶する。 065 private String[] fill_X = null; // スペースの文字列 066 private String[] fill_S = null; // ゼロの文字列 067 private String[] addSpc = null; // 内部変数。addLen で指定された文字数分の空白を管理します。 068 private final List<String[]> list = new ArrayList<String[]>(); 069 070 /** 071 * データの項目数を指定して、オブジェクトを構築します。 072 * 073 * @og.rev 5.6.6.0 (2013/07/05) addLen の代わりに、addSpc で管理します。 074 * 075 * @param len データの項目数 076 */ 077 public FixLengthData( final int len ) { 078 size = len ; 079 addLen = new int[size]; 080 type = new int[size]; 081 maxLen = new int[size]; 082 } 083 084 /** 085 * 項目間空白配列と各項目のタイプ配列を指定して、オブジェクトを構築します。 086 * どちらも、int型配列なので、順番に注意してください。 087 * 088 * @og.rev 5.6.6.0 (2013/07/05) 新規追加 089 * 090 * @param inAddLen データの項目間空白配列 091 * @param inType データの各項目のタイプ配列 092 * @see #setAddLength( int[] ) 093 * @see #setType( int[] ) 094 * @throws IllegalArgumentException 引数が null の場合 095 */ 096 public FixLengthData( final int[] inAddLen,final int[] inType ) { 097 if( inAddLen == null || inType == null ) { 098 String errMsg = "項目間空白配列 または、項目のタイプ配列に、null は、指定できません。"; 099 throw new IllegalArgumentException( errMsg ); 100 } 101 102 size = inAddLen.length ; 103 104 addLen = new int[size]; 105 type = new int[size]; 106 maxLen = new int[size]; 107 108 setAddLength( inAddLen ); 109 setType( inType ); 110 } 111 112 /** 113 * データの項目に対応した、固定時の間に挿入する空白文字数を指定します。 114 * 初期値は、0 です。 115 * 116 * @og.rev 5.6.6.0 (2013/07/05) addLen の代わりに、addSpc で管理します。 117 * 118 * @param inAddLen データの項目間空白配列 119 * @throws IllegalArgumentException 引数のデータ件数が、コンストラクタで指定した数と異なる場合 120 */ 121 public void setAddLength( final int[] inAddLen ) { 122 int len = (inAddLen == null) ? 0 : inAddLen.length ; 123 if( len != size ) { 124 String errMsg = "引数のデータ件数が、コンストラクタで指定した数と異なります。" 125 + "SIZE=[" + size + "] , 引数長=[" + len + "]" ; 126 throw new IllegalArgumentException( errMsg ); 127 } 128 129 System.arraycopy( inAddLen,0,addLen,0,size ); 130 } 131 132 /** 133 * データの各項目のタイプ(半角文字、数字)を指定します。 134 * X:半角文字の場合は、データを前方に、余った分を後方にスペースを埋めます。 135 * S:数字(前空白)の場合は、データを後方に、余った分を空白を前方に埋めます。 136 * S0:数字(前ゼロ)の場合は、データを後方に、余った分をゼロを前方に埋めます。 137 * K:半角全角混在の場合は、ENCODE(Windows-31J) で文字数を求めるとともに、X:半角文字と同様の処理を行います。 138 * 初期値は、X:半角文字 です。 139 * 140 * @param inType データの各項目のタイプ配列 141 * @see #X 142 * @see #S 143 * @see #S0 144 * @see #K 145 * @throws IllegalArgumentException 引数のデータ件数が、コンストラクタで指定した数と異なる場合 146 */ 147 public void setType( final int[] inType ) { 148 int len = (inType == null) ? 0 : inType.length ; 149 if( len != size ) { 150 String errMsg = "引数のデータ件数が、コンストラクタで指定した数と異なります。" 151 + "SIZE=[" + size + "] , 引数長=[" + len + "]" ; 152 throw new IllegalArgumentException( errMsg ); 153 } 154 155 System.arraycopy( inType,0,type,0,size ); 156 } 157 158 /** 159 * データの各項目に対応した配列データを設定します。 160 * 配列データを登録しながら、各項目の最大データ長をピックアップしていきます。 161 * 162 * @param inData データの各項目の配列データ 163 * @throws IllegalArgumentException 引数のデータ件数が、コンストラクタで指定した数と異なる場合 164 */ 165 public void addListData( final String[] inData ) { 166 int len = (inData == null) ? 0 : inData.length ; 167 if( len != size ) { 168 String errMsg = "引数のデータ件数が、コンストラクタで指定した数と異なります。" 169 + "SIZE=[" + size + "] , 引数長=[" + len + "]" ; 170 throw new IllegalArgumentException( errMsg ); 171 } 172 173 // 最大データ長の取得のみ行っておきます。 174 try { 175 for( int i=0; i<size; i++ ) { 176 if( inData[i] != null ) { 177 if( type[i] == K ) { 178 len = inData[i].getBytes( ENCODE ).length ; 179 } 180 else { 181 len = inData[i].length(); 182 } 183 if( maxLen[i] < len ) { maxLen[i] = len; } 184 } 185 } 186 } 187 catch( UnsupportedEncodingException ex ) { 188 String errMsg = "データの変換に失敗しました。[" + ENCODE + "]" ; 189 throw new RuntimeException( errMsg,ex ); 190 } 191 list.add( inData ); 192 } 193 194 /** 195 * 指定の行に対する固定文字数に設定された文字列を返します。 196 * 引数の行番号は、addListData(String[])メソッドで登録された順番です。 197 * 198 * @og.rev 5.6.6.0 (2013/07/05) addLen の代わりに、addSpc で管理します。 199 * 200 * @param line 行番号(addListData で登録した順) 201 * 202 * @return 固定文字数に設定された文字列 203 */ 204 public String getFixData( final int line ) { 205 if( fill_X == null ) { makeSpace(); } // 初期処理 206 207 String[] data = list.get( line ); 208 StringBuilder rtn = new StringBuilder(); 209 for( int i=0; i<size; i++ ) { 210 String dt = ( data[i] == null ) ? "" : data[i] ; 211 switch( type[i] ) { 212 case X: // 文字を出力してから、スペースで埋める。 213 rtn.append( dt ); 214 rtn.append( fill_X[i].substring( dt.length() ) ); 215 break; 216 case S: // 空白で埋めてから、文字を出力する。 217 rtn.append( fill_X[i].substring( dt.length() ) ); 218 rtn.append( dt ); 219 break; 220 case S0: // ゼロで埋めてから、文字を出力する。 221 rtn.append( fill_S[i].substring( dt.length() ) ); 222 rtn.append( dt ); 223 break; 224 case K: // 全角を含む文字を出力してから、スペースで埋める。 225 try { 226 int len = dt.getBytes( ENCODE ).length ; 227 rtn.append( dt ); 228 rtn.append( fill_X[i].substring( len ) ); 229 } 230 catch( UnsupportedEncodingException ex ) { 231 String errMsg = "データの変換に失敗しました。[" + ENCODE + "]" ; 232 throw new RuntimeException( errMsg,ex ); 233 } 234 break; 235 default: // 基本的にありえない 236 String errMsg = "不正な種別が指定されました[" + type[i] + "]" ; 237 throw new RuntimeException( errMsg ); 238 // break; 239 } 240 rtn.append( addSpc[i] ); // 5.6.6.0 (2013/07/05) 項目間のスペースを出力 241 } 242 return rtn.toString(); 243 } 244 245 /** 246 * データの各項目に対応した配列データを、すべて設定します。 247 * ここでは、配列の配列型データを受け取り、内部的に、addListData( String[] )を 248 * 実行しています。 249 * 簡易的なメソッドです。 250 * 251 * @og.rev 5.6.6.0 (2013/07/05) 新規追加 252 * 253 * @param inData データの各項目の配列データの配列 254 * @see #addListData( String[] ) 255 * @throws IllegalArgumentException 引数のデータ件数が、コンストラクタで指定した数と異なる場合 256 */ 257 public void addAllListData( final String[][] inData ) { 258 for( int i=0; i<inData.length; i++ ) { 259 addListData( inData[i] ); 260 } 261 } 262 263 /** 264 * 内部登録済みのすべてのデータを連結して出力します。 265 * 連結時には、改行コードを設定しています。 266 * 267 * @og.rev 5.6.6.0 (2013/07/05) getAllFixData( StringBuilder ) を使用するように内部処理を変更 268 * 269 * @return 固定文字数に設定された文字列 270 * @see #getFixData( int ) 271 * @see #getAllFixData( StringBuilder ) 272 */ 273 public String getAllFixData() { 274 return getAllFixData( new StringBuilder( 1000 ) ).toString(); 275 } 276 277 /** 278 * 内部登録済みのすべてのデータを引数のStringBuilderに連結して返します。 279 * 連結時には、改行コードを設定しています。 280 * return オブジェクトは、この引数と同一のオブジェクトです。 281 * 282 * @og.rev 5.6.6.0 (2013/07/05) 新規追加 283 * 284 * @param buf 連結に使用する StringBuilder 285 * @return 固定文字数に設定された StringBuilder(入力と同じ) 286 * @see #getFixData( int ) 287 * @see #getAllFixData() 288 */ 289 public StringBuilder getAllFixData( final StringBuilder buf ) { 290 int len = list.size(); 291 for( int i=0; i<len; i++ ) { 292 buf.append( getFixData( i ) ).append( CR ); 293 } 294 295 return buf; 296 } 297 298 /** 299 * 固定文字列を作成するための種となるスペース文字列とゼロ文字列を作成します。 300 * 301 * @og.rev 5.6.6.0 (2013/07/05) addLen の代わりに、addSpc で管理します。 302 */ 303 private void makeSpace() { 304 fill_X = new String[size]; 305 fill_S = new String[size]; 306 addSpc = new String[size]; 307 char[] ch ; 308 309 int startCnt = 0; // 先頭からの文字数 310 for( int i=0; i<size; i++ ) { 311 // addLen に、T(タブ)が指定された場合、addSpc は、4の倍数になるように調整する。 312 startCnt += maxLen[i]; 313 int addCnt = addLen[i] ; 314 if( addCnt < 0 ) { // T,T2,T3,T4 のケース 315 // addSpc[i] = TAB[-addCnt]; 316 addCnt = (-4 * addCnt) - (startCnt % 4); // TAB数に合わせたスペースに換算した数 317 } 318 // else { 319 ch = new char[addCnt]; 320 Arrays.fill( ch, ' ' ); 321 addSpc[i] = String.valueOf( ch ); 322 // } 323 startCnt += addCnt ; 324 325 ch = new char[maxLen[i]]; 326 switch( type[i] ) { 327 case S0: 328 Arrays.fill( ch, '0' ); 329 fill_S[i] = String.valueOf( ch ); 330 break; 331 case X: 332 case S: 333 case K: 334 Arrays.fill( ch, ' ' ); 335 fill_X[i] = String.valueOf( ch ); 336 break; 337 default: // 基本的にありえない 338 String errMsg = "不正な種別が指定されました[" + type[i] + "]" ; 339 throw new RuntimeException( errMsg ); 340 // break; 341 } 342 } 343 } 344 345 /** 346 * 内部変数のデータと、最大値のキャッシュをクリアします。 347 * 348 * それ以外の変数(size、addLength、type)は、設定時のまま残っています。 349 * 350 */ 351 public void clear() { 352 list.clear() ; 353 maxLen = new int[size]; 354 fill_X = null; // スペースの文字列 355 fill_S = null; // ゼロの文字列 356 addSpc = null; // 項目間空白 357 } 358}