View Javadoc
1   package com.github.mygreen.cellformatter.number;
2   
3   import java.math.RoundingMode;
4   import java.text.DecimalFormat;
5   
6   import com.github.mygreen.cellformatter.ConditionNumberFormatter;
7   
8   
9   /**
10   * 小数表現を含む数値を表現するクラス。
11   * <p>{@link ConditionNumberFormatter}でフォーマットする際に利用する。
12   * 
13   * @author T.TSUCHIE
14   *
15   */
16  public class DecimalNumber extends FormattedNumber {
17      
18      /**
19       * 精度(小数の精度)
20       * ・小数を持たない場合は、ゼロを設定する。
21       */
22      protected final int scale;
23      
24      /**
25       * 整数部分。
26       * ・0以下の場合は、空文字。
27       * ・符号はつかない。
28       */
29      protected String integerPart;
30      
31      /**
32       * 小数部分。
33       * ・精度が0以上場合は、空文字。
34       */
35      protected String decimalPart;
36      
37      /**
38       * 千分率(パーミル)の次数。
39       * ・0のとき、何もしない。
40       * ・1のとき、1000で割る。
41       * ・2のとき、1000^2で割る。
42       */
43      protected int permilles;
44      
45      public DecimalNumber(final double value, final int scale, final int permilles) {
46          super(value);
47          this.scale = scale > 0 ? scale : 0;
48          this.permilles = permilles > 0 ? permilles : 0;
49          
50          init();
51      }
52      
53      public DecimalNumber(final double value, final int scale) {
54          this(value, scale, 0);
55      }
56      
57      /**
58       * 値を精度に従い整数部と小数部に分解する。
59       */
60      protected void init() {
61          
62          if(isZero()) {
63              this.integerPart = "";
64              this.decimalPart = "";
65              return;
66          }
67          
68          final StringBuilder sb = new StringBuilder();
69          sb.append("#");
70          if(scale > 0) {
71              sb.append(".");
72          }
73          
74          // 小数の精度分、書式を追加する。
75          for(int i=0; i < scale; i++) {
76              sb.append("#");
77          }
78          
79          final DecimalFormat format = new DecimalFormat(sb.toString());
80          format.setRoundingMode(RoundingMode.HALF_UP);
81          
82          double num = Math.abs(getValue());
83          if(getPermilles() > 0) {
84              num /= Math.pow(1000, getPermilles());
85          }
86          
87          String str = format.format(num);
88          
89          // 数値を小数部と整数部に分割する。
90          setupIntegerAndDecimalPart(str);
91          
92      }
93      
94      /**
95       * 文字列形式の数値を整数部と小数部に分割し、各フィールドに設定する
96       * @param str
97       */
98      protected void setupIntegerAndDecimalPart(final String str) {
99          
100         final int dotIdx = str.indexOf(".");
101         if(dotIdx < 0) {
102             // 整数部のみの場合
103             this.integerPart = str;
104             this.decimalPart = "";
105         } else {
106             this.integerPart = str.substring(0, dotIdx);
107             if(this.integerPart.equals("0")) {
108                 this.integerPart = "";
109             }
110             
111             this.decimalPart = str.substring(dotIdx+1);
112             
113         }
114     }
115     
116     /**
117      * 小数の精度を取得する。
118      * ・小数を持たない場合は、0を返す。
119      * @return
120      */
121     public int getScale() {
122         return scale;
123     }
124     
125     /**
126      * 整数部のフォーマットした値を取得する。
127      * @return
128      */
129     public String getIntegerPart() {
130         return integerPart;
131     }
132     
133     /**
134      * 整数部の指定した桁の値を取得する。
135      * @param digit 1から始まる。
136      * @return その桁の値がない場合は空文字を返す。
137      */
138     public String getIntegerPart(final int digit) {
139         
140         final int length = integerPart.length();
141         if(length < digit || digit <= 0) {
142             return "";
143         }
144         
145         String num = String.valueOf(integerPart.charAt(length - digit));
146         if(isUseSeparator()) {
147             if(digit >= 4 && (digit-1) % 3 == 0) {
148                 num += ",";
149             }
150         }
151         
152         return num;
153         
154     }
155     
156     /**
157      * 整数部の指定した桁以降の値を取得する。
158      * @param digit 1から始まる。
159      * @return その桁の値がない場合は空文字を返す。
160      */
161     public String getIntegerPartAfter(final int digit) {
162         
163         final int length = integerPart.length();
164         if(length < digit || digit <= 0) {
165             return "";
166         }
167         
168         String num = integerPart.substring(0, (length - digit + 1));
169         if(isUseSeparator() && digit >= 4) {
170             // 区切り文字を入れるために分割する。
171             StringBuilder sb = new StringBuilder();
172             for(int i=0; i < num.length(); i++) {
173                 char c = num.charAt(i);
174                 sb.append(c);
175                 
176                 // 現在の処理中の桁数
177                 int itemDigit = length -i;
178                 if((itemDigit >= 3) && (itemDigit -1) % 3 == 0) {
179                     sb.append(",");
180                 }
181             }
182             
183             num = sb.toString();
184         }
185         
186         return num;
187         
188     }
189     
190     /**
191      * 小数部のフォーマットした値を取得する。
192      * @return
193      */
194     public String getDecimalPart() {
195         return decimalPart;
196     }
197     
198     /**
199      * 小数部の指定した桁の値を取得する。
200      * @param digit 1から始まる。
201      * @return その桁の値がない場合は空文字を返す。
202      */
203     public String getDecimalPart(final int digit) {
204         
205         final int length = decimalPart.length();
206         if(length < digit || digit <= 0) {
207             return "";
208         }
209         
210         return String.valueOf(decimalPart.charAt(digit-1));
211         
212     }
213     
214     
215     
216     @Override
217     public String toString() {
218         StringBuilder sb = new StringBuilder();
219         
220         if(isNegative()) {
221             sb.append("-");
222         }
223         
224         if(getIntegerPart().isEmpty()) {
225             sb.append("0");
226         }
227         
228         if(!getDecimalPart().isEmpty()) {
229             sb.append(".").append(getDecimalPart());
230         }
231         
232         return sb.toString();
233     }
234     
235     /**
236      * 千分率(パーミル)の次数を取得する
237      * @return
238      */
239     public int getPermilles() {
240         return permilles;
241     }
242     
243 }