package railo.runtime.util; import java.math.RoundingMode; import java.text.DecimalFormat; import java.util.Locale; import railo.commons.lang.StringUtil; /** * Number formation class */ public final class NumberFormat { private static byte LEFT = 0; private static byte CENTER = 1; private static byte RIGHT = 2; /** * formats a number * @param number * @return formatted number as string */ public String format(Locale locale,double number) { DecimalFormat df=getDecimalFormat(locale); df.applyPattern(",0"); df.setGroupingSize(3); return df.format(number).replace('\'',','); } /** * format a number with given mask * @param number * @param mask * @return formatted number as string * @throws InvalidMaskException */ public String format(Locale locale,double number, String mask) throws InvalidMaskException { byte justification = RIGHT; boolean useBrackets = false; boolean usePlus = false; boolean useMinus = false; boolean useDollar = false; boolean useComma = false; boolean foundDecimal = false; boolean symbolsFirst = false; boolean foundZero=false; int maskLen = mask.length(); if(maskLen == 0) throw new InvalidMaskException("mask can't be a empty value"); StringBuffer maskBuffer = new StringBuffer(mask); String mod=StringUtil.replace(mask, ",", "", true); if(StringUtil.startsWith(mod, '_'))symbolsFirst = true; if(mask.startsWith(",.")) { maskBuffer.replace(0, 1, ",0"); } //if(maskBuffer.charAt(0) == '.')maskBuffer.insert(0, '0'); //print.out(maskBuffer); boolean addZero=false; for(int i = 0; i < maskBuffer.length();) { boolean removeChar = false; switch(maskBuffer.charAt(i)) { case '_': case '9': if(foundDecimal || foundZero) maskBuffer.setCharAt(i, '0'); else maskBuffer.setCharAt(i, '#');// # break; case '.': if(i>0 && maskBuffer.charAt(i-1)=='#')maskBuffer.setCharAt(i-1, '0'); if(foundDecimal) removeChar = true; else foundDecimal = true; if(i==0)addZero=true; break; case '(': case ')': useBrackets = true; removeChar = true; break; case '+': usePlus = true; removeChar = true; break; case '-': useMinus = true; removeChar = true; break; case ',': useComma = true; if(true) { removeChar = true; maskLen++; } break; case 'L': justification = LEFT; removeChar = true; break; case 'C': justification = CENTER; removeChar = true; break; case '$': useDollar = true; removeChar = true; break; case '^': removeChar = true; break; case '0': if(!foundDecimal){ for(int y = 0; y < i;y++) { if(maskBuffer.charAt(y)=='#') maskBuffer.setCharAt(y, '0'); } } foundZero=true; break; default: throw new InvalidMaskException("invalid character ["+maskBuffer.charAt(i)+"], valid characters are ['_', '9', '.', '0', '(', ')', '+', '-', ',', 'L', 'C', '$', '^']"); } if(removeChar) { maskBuffer.deleteCharAt(i); maskLen--; } else { i++; } } if(addZero) maskBuffer.insert(0, '0'); mask = new String(maskBuffer); maskLen=mask.length(); DecimalFormat df = getDecimalFormat(locale);//(mask); int gs=df.getGroupingSize(); df.applyPattern(mask); df.setGroupingSize(gs); df.setGroupingUsed(useComma); df.setRoundingMode(RoundingMode.HALF_UP); String formattedNum = df.format(StrictMath.abs(number)); StringBuffer formattedNumBuffer = new StringBuffer(formattedNum); if(symbolsFirst) { int widthBefore = formattedNumBuffer.length(); applySymbolics(formattedNumBuffer, number, usePlus, useMinus, useDollar, useBrackets); int offset = formattedNumBuffer.length() - widthBefore; if(formattedNumBuffer.length() < maskLen + offset) { int padding = (maskLen + offset) - formattedNumBuffer.length(); applyJustification(formattedNumBuffer,justification, padding); } } else { int widthBefore = formattedNumBuffer.length(); StringBuffer temp = new StringBuffer(formattedNumBuffer.toString()); applySymbolics(temp, number, usePlus, useMinus, useDollar, useBrackets); int offset = temp.length() - widthBefore; if(temp.length() < maskLen + offset) { int padding = (maskLen + offset) - temp.length(); applyJustification(formattedNumBuffer,justification, padding); } applySymbolics(formattedNumBuffer, number, usePlus, useMinus, useDollar, useBrackets); } /*/ TODO better impl, this is just a quick fix formattedNum=formattedNumBuffer.toString(); int index=formattedNum.indexOf('.'); if(index==0) { formattedNumBuffer.insert(0, '0'); formattedNum=formattedNumBuffer.toString(); } else if(index>0){ } String tmp=formattedNum.trim(); if(tmp.length()>0 && tmp.charAt(0)=='.') */ return formattedNumBuffer.toString(); } private void applyJustification(StringBuffer _buffer, int _just, int padding) { if(_just == CENTER) centerJustify(_buffer, padding); else if(_just == LEFT) leftJustify(_buffer, padding); else rightJustify(_buffer, padding); } private void applySymbolics(StringBuffer _buffer, double _no, boolean _usePlus, boolean _useMinus, boolean _useDollar, boolean _useBrackets) { if(_useBrackets && _no < 0.0D) { _buffer.insert(0, '('); _buffer.append(')'); } if(_usePlus) _buffer.insert(0, _no <= 0.0D ? '-' : '+'); if(_no < 0.0D && !_useBrackets && !_usePlus) _buffer.insert(0, '-'); else if(_useMinus) _buffer.insert(0, ' '); if(_useDollar) _buffer.insert(0, '$'); } private void centerJustify(StringBuffer _src, int _padding) { int padSplit = _padding / 2 + 1; rightJustify(_src, padSplit); leftJustify(_src, padSplit); } private void rightJustify(StringBuffer _src, int _padding) { for(int x = 0; x < _padding; x++) _src.insert(0, ' '); } private void leftJustify(StringBuffer _src, int _padding) { for(int x = 0; x < _padding; x++) _src.append(' '); } private DecimalFormat getDecimalFormat(Locale locale) { java.text.NumberFormat format = java.text.NumberFormat.getInstance(locale); if(format instanceof DecimalFormat) { return ((DecimalFormat)format); } return new DecimalFormat(); } }