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