001 package railo.runtime.util; 002 003 import java.math.RoundingMode; 004 import java.text.DecimalFormat; 005 import java.util.Locale; 006 007 import railo.commons.lang.StringUtil; 008 009 010 /** 011 * Number formation class 012 */ 013 public final class NumberFormat { 014 015 private static byte LEFT = 0; 016 private static byte CENTER = 1; 017 private static byte RIGHT = 2; 018 019 /** 020 * formats a number 021 * @param number 022 * @return formatted number as string 023 */ 024 public String format(Locale locale,double number) { 025 026 DecimalFormat df=getDecimalFormat(locale); 027 df.applyPattern(",0"); 028 df.setGroupingSize(3); 029 030 031 return df.format(number).replace('\'',','); 032 } 033 034 /** 035 * format a number with given mask 036 * @param number 037 * @param mask 038 * @return formatted number as string 039 * @throws InvalidMaskException 040 */ 041 public String format(Locale locale,double number, String mask) throws InvalidMaskException { 042 byte justification = RIGHT; 043 044 boolean useBrackets = false; 045 boolean usePlus = false; 046 boolean useMinus = false; 047 boolean useDollar = false; 048 boolean useComma = false; 049 boolean foundDecimal = false; 050 boolean symbolsFirst = false; 051 boolean foundZero=false; 052 053 int maskLen = mask.length(); 054 if(maskLen == 0) throw new InvalidMaskException("mask can't be a empty value"); 055 056 057 058 StringBuffer maskBuffer = new StringBuffer(mask); 059 060 String mod=StringUtil.replace(mask, ",", "", true); 061 if(StringUtil.startsWith(mod, '_'))symbolsFirst = true; 062 if(mask.startsWith(",.")) { 063 maskBuffer.replace(0, 1, ",0"); 064 } 065 //if(maskBuffer.charAt(0) == '.')maskBuffer.insert(0, '0'); 066 //print.out(maskBuffer); 067 boolean addZero=false; 068 for(int i = 0; i < maskBuffer.length();) { 069 070 boolean removeChar = false; 071 switch(maskBuffer.charAt(i)) { 072 case '_': 073 case '9': 074 if(foundDecimal || foundZero) maskBuffer.setCharAt(i, '0'); 075 else maskBuffer.setCharAt(i, '#');// # 076 break; 077 078 case '.': 079 if(i>0 && maskBuffer.charAt(i-1)=='#')maskBuffer.setCharAt(i-1, '0'); 080 if(foundDecimal) removeChar = true; 081 else foundDecimal = true; 082 if(i==0)addZero=true; 083 break; 084 085 case '(': 086 case ')': 087 useBrackets = true; 088 removeChar = true; 089 break; 090 091 case '+': 092 usePlus = true; 093 removeChar = true; 094 break; 095 096 case '-': 097 useMinus = true; 098 removeChar = true; 099 break; 100 101 case ',': 102 useComma = true; 103 if(true) { 104 removeChar = true; 105 maskLen++; 106 } 107 break; 108 109 case 'L': 110 justification = LEFT; 111 removeChar = true; 112 break; 113 114 case 'C': 115 justification = CENTER; 116 removeChar = true; 117 break; 118 119 case '$': 120 useDollar = true; 121 removeChar = true; 122 break; 123 124 case '^': 125 removeChar = true; 126 break; 127 128 case '0': 129 if(!foundDecimal){ 130 for(int y = 0; y < i;y++) { 131 if(maskBuffer.charAt(y)=='#') 132 maskBuffer.setCharAt(y, '0'); 133 } 134 } 135 foundZero=true; 136 break; 137 138 default: 139 throw new InvalidMaskException("invalid charcter ["+maskBuffer.charAt(i)+"], valid characters are ['_', '9', '.', '0', '(', ')', '+', '-', ',', 'L', 'C', '$', '^']"); 140 141 } 142 if(removeChar) { 143 maskBuffer.deleteCharAt(i); 144 maskLen--; 145 } 146 else { 147 i++; 148 } 149 } 150 151 if(addZero) 152 maskBuffer.insert(0, '0'); 153 154 155 mask = new String(maskBuffer); 156 maskLen=mask.length(); 157 DecimalFormat df = getDecimalFormat(locale);//(mask); 158 int gs=df.getGroupingSize(); 159 df.applyPattern(mask); 160 df.setGroupingSize(gs); 161 df.setGroupingUsed(useComma); 162 df.setRoundingMode(RoundingMode.HALF_UP); 163 164 String formattedNum = df.format(StrictMath.abs(number)); 165 StringBuffer formattedNumBuffer = new StringBuffer(formattedNum); 166 if(symbolsFirst) { 167 int widthBefore = formattedNumBuffer.length(); 168 applySymbolics(formattedNumBuffer, number, usePlus, useMinus, useDollar, useBrackets); 169 int offset = formattedNumBuffer.length() - widthBefore; 170 171 if(formattedNumBuffer.length() < maskLen + offset) { 172 int padding = (maskLen + offset) - formattedNumBuffer.length(); 173 applyJustification(formattedNumBuffer,justification, padding); 174 } 175 176 177 178 } 179 else { 180 int widthBefore = formattedNumBuffer.length(); 181 182 StringBuffer temp = new StringBuffer(formattedNumBuffer.toString()); 183 applySymbolics(temp, number, usePlus, useMinus, useDollar, useBrackets); 184 int offset = temp.length() - widthBefore; 185 186 if(temp.length() < maskLen + offset) { 187 int padding = (maskLen + offset) - temp.length(); 188 applyJustification(formattedNumBuffer,justification, padding); 189 } 190 applySymbolics(formattedNumBuffer, number, usePlus, useMinus, useDollar, useBrackets); 191 } 192 /*/ TODO better impl, this is just a quick fix 193 formattedNum=formattedNumBuffer.toString(); 194 195 int index=formattedNum.indexOf('.'); 196 if(index==0) { 197 formattedNumBuffer.insert(0, '0'); 198 formattedNum=formattedNumBuffer.toString(); 199 } 200 else if(index>0){ 201 202 } 203 204 String tmp=formattedNum.trim(); 205 if(tmp.length()>0 && tmp.charAt(0)=='.') 206 */ 207 return formattedNumBuffer.toString(); 208 } 209 210 211 212 private void applyJustification(StringBuffer _buffer, int _just, int padding) { 213 if(_just == CENTER) centerJustify(_buffer, padding); 214 else if(_just == LEFT) leftJustify(_buffer, padding); 215 else rightJustify(_buffer, padding); 216 } 217 218 private void applySymbolics(StringBuffer _buffer, double _no, boolean _usePlus, boolean _useMinus, boolean _useDollar, boolean _useBrackets) { 219 if(_useBrackets && _no < 0.0D) { 220 _buffer.insert(0, '('); 221 _buffer.append(')'); 222 } 223 if(_usePlus) 224 _buffer.insert(0, _no <= 0.0D ? '-' : '+'); 225 if(_no < 0.0D && !_useBrackets && !_usePlus) 226 _buffer.insert(0, '-'); 227 else 228 if(_useMinus) 229 _buffer.insert(0, ' '); 230 if(_useDollar) 231 _buffer.insert(0, '$'); 232 } 233 234 private void centerJustify(StringBuffer _src, int _padding) { 235 int padSplit = _padding / 2 + 1; 236 rightJustify(_src, padSplit); 237 leftJustify(_src, padSplit); 238 } 239 240 private void rightJustify(StringBuffer _src, int _padding) { 241 for(int x = 0; x < _padding; x++) 242 _src.insert(0, ' '); 243 244 } 245 246 private void leftJustify(StringBuffer _src, int _padding) { 247 for(int x = 0; x < _padding; x++) 248 _src.append(' '); 249 250 } 251 252 private DecimalFormat getDecimalFormat(Locale locale) { 253 java.text.NumberFormat format = java.text.NumberFormat.getInstance(locale); 254 if(format instanceof DecimalFormat) { 255 return ((DecimalFormat)format); 256 257 } 258 return new DecimalFormat(); 259 } 260 261 }