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