//////////////////////////////////////////////////////////////////////////////// // // Licensed to the Apache Software Foundation (ASF) under one or more // contributor license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright ownership. // The ASF licenses this file to You under the Apache License, Version 2.0 // (the "License"); you may not use this file except in compliance with // the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // //////////////////////////////////////////////////////////////////////////////// package mx.formatters { /** * The NumberBase class is a utility class that contains * general number formatting capabilities, including rounding, * precision, thousands formatting, and negative sign formatting. * The implementation of the formatter classes use this class. * * @see mx.formatters.NumberFormatter * @see mx.formatters.NumberBaseRoundType * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public class NumberBase { include "../core/Version.as"; //-------------------------------------------------------------------------- // // Constructor // //-------------------------------------------------------------------------- /** * Constructor. * * @param decimalSeparatorFrom Decimal separator to use * when parsing an input String. * * @param thousandsSeparatorFrom Character to use * as the thousands separator in the input String. * * @param decimalSeparatorTo Decimal separator character to use * when outputting formatted decimal numbers. * * @param thousandsSeparatorTo Character to use * as the thousands separator in the output String. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function NumberBase(decimalSeparatorFrom:String = ".", thousandsSeparatorFrom:String = ",", decimalSeparatorTo:String = ".", thousandsSeparatorTo:String = ",") { super(); this.decimalSeparatorFrom = decimalSeparatorFrom; this.thousandsSeparatorFrom = thousandsSeparatorFrom; this.decimalSeparatorTo = decimalSeparatorTo; this.thousandsSeparatorTo = thousandsSeparatorTo; isValid = true; } //-------------------------------------------------------------------------- // // Properties // //-------------------------------------------------------------------------- //---------------------------------- // decimalSeparatorFrom //---------------------------------- /** * Decimal separator character to use * when parsing an input String. * * @default "." * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public var decimalSeparatorFrom:String; //---------------------------------- // decimalSeparatorTo //---------------------------------- /** * Decimal separator character to use * when outputting formatted decimal numbers. * * @default "." * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public var decimalSeparatorTo:String; //---------------------------------- // isValid //---------------------------------- /** * If true, the format succeeded, * otherwise it is false. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public var isValid:Boolean = false; //---------------------------------- // thousandsSeparatorFrom //---------------------------------- /** * Character to use as the thousands separator * in the input String. * * @default "," * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public var thousandsSeparatorFrom:String; //---------------------------------- // thousandsSeparatorTo //---------------------------------- /** * Character to use as the thousands separator * in the output String. * * @default "," * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public var thousandsSeparatorTo:String; //-------------------------------------------------------------------------- // // Methods // //-------------------------------------------------------------------------- /** * Formats a number by rounding it. * The possible rounding types are defined by * mx.formatters.NumberBaseRoundType. * * @param value Value to be rounded. * * @param roundType The type of rounding to perform: * NumberBaseRoundType.NONE, NumberBaseRoundType.UP, * NumberBaseRoundType.DOWN, or NumberBaseRoundType.NEAREST. * * @return Formatted number. * * @see mx.formatters.NumberBaseRoundType * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function formatRounding(value:String, roundType:String):String { var v:Number = Number(value); if (roundType != NumberBaseRoundType.NONE) { if (roundType == NumberBaseRoundType.UP) { v = Math.ceil(v); } else if (roundType == NumberBaseRoundType.DOWN) { v = Math.floor(v); } else if (roundType == NumberBaseRoundType.NEAREST) { v = Math.round(v); } else { isValid = false; return ""; } } return v.toString(); } /** * Formats a number by rounding it and setting the decimal precision. * The possible rounding types are defined by * mx.formatters.NumberBaseRoundType. * * @param value Value to be rounded. * * @param roundType The type of rounding to perform: * NumberBaseRoundType.NONE, NumberBaseRoundType.UP, * NumberBaseRoundType.DOWN, or NumberBaseRoundType.NEAREST. * * @param precision int of decimal places to use. * * @return Formatted number. * * @see mx.formatters.NumberBaseRoundType * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function formatRoundingWithPrecision(value:String, roundType:String, precision:int):String { // precision works differently now. Its default value is -1 // which means 'do not alter the number's precision'. If a precision // value is set, all numbers will contain that precision. Otherwise, there // precision will not be changed. var v:Number = Number(value); // If rounding is not present and precision is NaN, // leave value untouched. if (roundType == NumberBaseRoundType.NONE) { if (precision == -1) return v.toString(); } else { // If rounding is present but precision is less than 0, // then do integer rounding. if (precision < 0) precision = 0; // Shift decimal right as Math functions // perform only integer ceil/round/floor. v = v * Math.pow(10, precision); // Attempt to get rid of floating point errors v = Number(v.toString()); if (roundType == NumberBaseRoundType.UP) { v = Math.ceil(v); } else if (roundType == NumberBaseRoundType.DOWN) { v = Math.floor(v); } else if (roundType == NumberBaseRoundType.NEAREST) { v = Math.round(v); } else { isValid = false; return ""; } // Shift decimal left to get back decimal to original point. v = v / Math.pow(10, precision); } return v.toString(); } /** * Formats a number by replacing the default decimal separator, ".", * with the decimal separator specified by decimalSeparatorTo. * * @param value The String value of the Number * (formatted American style ####.##). * * @return String representation of the input where "." is replaced * with the decimal formatting character. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function formatDecimal(value:String):String { var parts:Array = value.split("."); return parts.join(decimalSeparatorTo); } /** * Formats a number by using * the thousandsSeparatorTo property as the thousands separator * and the decimalSeparatorTo property as the decimal separator. * * @param value Value to be formatted. * * @return Formatted number. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function formatThousands(value:String):String { var v:Number = Number(value); var isNegative:Boolean = (v < 0); var numStr:String = Math.abs(v).toString(); numStr.toLowerCase(); var e:int = numStr.indexOf("e") if (e != -1) //deal with exponents numStr = expandExponents(numStr); var numArr:Array = numStr.split((numStr.indexOf(decimalSeparatorTo) != -1) ? decimalSeparatorTo : "."); var numLen:int = String(numArr[0]).length; if (numLen > 3) { var numSep:int = int(Math.floor(numLen / 3)); if ((numLen % 3) == 0) numSep--; var b:int = numLen; var a:int = b - 3; var arr:Array = []; for (var i:int = 0; i <= numSep; i++) { arr[i] = numArr[0].slice(a, b); a = int(Math.max(a - 3, 0)); b = int(Math.max(b - 3, 1)); } arr.reverse(); numArr[0] = arr.join(thousandsSeparatorTo); } numStr = numArr.join(decimalSeparatorTo); if (isNegative) numStr = "-" + numStr; return numStr.toString(); } /** * Formats a number by setting its decimal precision by using * the decimalSeparatorTo property as the decimal separator. * * @param value Value to be formatted. * * @param precision Number of decimal points to use. * * @return Formatted number. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function formatPrecision(value:String, precision:int):String { // precision works differently now. Its default value is -1 // which stands for 'do not alter the number's precision'. If a precision // value is set, all numbers will contain that precision. Otherwise, there // precision will not be changed. if (precision == -1) return value; var numArr:Array = value.split(decimalSeparatorTo); numArr[0] = numArr[0].length == 0 ? "0" : numArr[0]; if (precision > 0) { var decimalVal:String = numArr[1] ? String(numArr[1]) : ""; var fraction:String = decimalVal + "000000000000000000000000000000000"; value = numArr[0] + decimalSeparatorTo + fraction.substr(0, precision); } else { value = String(numArr[0]); } return value.toString(); } /** * Formats a negative number with either a minus sign (-) * or parentheses (). * * @param value Value to be formatted. * * @param useSign If true, use a minus sign (-). * If false, use parentheses (). * * @return Formatted number. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function formatNegative(value:String, useSign:Boolean):String { if (useSign) { if (value.charAt(0) != "-") value = "-" + value; } else if (!useSign) { if (value.charAt(0) == "-") value = value.substr(1, value.length - 1); value = "(" + value + ")"; } else { isValid = false; return ""; } return value; } /** * Extracts a number from a formatted String. * Examines the String from left to right * and returns the first number sequence. * Ignores thousands separators and includes the * decimal and numbers trailing the decimal. * * @param str String to parse for the numeric value. * * @return Value, which can be a decimal. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function parseNumberString(str:String):String { // Check the decimal and thousands formatting for validity. var splitDec:Array = str.split(decimalSeparatorFrom); if (splitDec.length > 2) return null; // Attempt to extract the first number sequence from the string. var len:int = str.length; var count:int = 0; var letter:String; var num:String; var isNegative:Boolean = false; while (count < len) { letter = str.charAt(count); count++; if (("0" <= letter && letter <= "9") || (letter == decimalSeparatorFrom)) { var lastLetter:String = str.charAt(count - 2); // We must handle cases where we have negative input like "-YTL5.000,00" // and currencySymbol is longer than one character. if ((lastLetter == "-") || (str.charAt(0) == "-")) isNegative = true; num = ""; count--; for (var i:int = count; i < len; i++) { letter = str.charAt(count); count++; if ("0" <= letter && letter <= "9") num += letter; else if (letter == decimalSeparatorFrom) num += "."; else if (letter != thousandsSeparatorFrom || count >= len) break; } } } // there are all sorts of variations of zero, such as: // .0 0. 0.0 0000 0000.00000 -0 // Here, we simply convert to a 'real' Number and see if // it's resolved to zero. if it does, just return a zero // string and be done with it. if ((num != null) && (str != '')) { var n:Number = Number(num); if (n == 0) return '0'; } // if the last digit is the dot, whack it if (num) { if (num.charAt(num.length-1) == '.') { // we have something like 33. if (num.length >= 2) { num = num.substring(0, num.length-1); } // we have merely . else if (num.length == 1) { num = ''; isNegative = false; } } } return isNegative ? "-" + num : num; } /** * Formats a number in exponent notation, into * a number in decimal notation. * * @param str String to process in exponent notation. * * @return Formatted number. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function expandExponents(value:String):String { //Break string into component parts var regExp:RegExp = /^([+-])?(\d+).?(\d*)[eE]([-+]?\d+)$/; var result:Array = regExp.exec(value); var sign:String = result[1]; var first:String = result[2]; var last:String = result[3]; var exp:int = int(result[4]); //if we didn't get a good exponent to begin with, return what we can figure out if (!exp) { return (sign ? sign : "") + (first ? first : "0") + (last ? "." + last : ""); } var r:String = first + last; var decimal:Boolean = exp < 0; if (decimal) { var o:Number = -1 * (first.length + exp) + 1; return (sign ? sign : "") + "0." + new Array(o).join("0") + r; } else { var i:Number = exp + first.length; if (i >= r.length) return (sign ? sign : "") + r + new Array(i - r.length + 1).join("0"); else return (sign ? sign : "") + r.substr(0,i) + "." + r.substr(i); } } } }