import ascb.util.Locale; class ascb.util.NumberFormat { private var _sMask:String; /** * Get and set the mask for the formatting. The mask can consist of 0's, #'s, * commas, and dots. */ public function get mask():String { return _sMask; } public function set mask(sMask:String):Void { _sMask = sMask; } function NumberFormat(sMask:String) { _sMask = sMask; } /** * Format a number. If no mask has been set then the standard formatting * for the locale is used. Optionally, you may specify radix, prefix, locale, * and/or symbol object parameters. *

* Example usage:
* trace(nfFormatter.format(1000)); // Displays 1,000
* trace(nfFormatter.format(1000, 16)); // Displays: 0x3E8
* trace(nfFormatter.format(1000, 16, "#")); // Displays: #3E8
* trace(nfFormatter.format(1000, new Locale("fr"))); // Displays: 1.000
* trace(nfFormatter.format(1000, {group: "|", decimal: "%"})); // Displays: 1|000
*

* to the nearest of a specified interval. * @param number The number you want to format. * @param radix (optional) The radix by which to display the number. * @param prefix (optional) The prefix to use when specifying the radix.ber. * @param locale (optional) A Locale object. * @param symbols object (optional) An object specifying the group and decimal symbols. * @return The formatted number as a string. */ public function format(nNumber:Number):String { // Check to see if the second parameter is a number. If so, that means it's the radix, // so format the number based on the radix. if(typeof arguments[1] == "number") { var nRadix:Number = Number(arguments[1]); var sNumber:String = nNumber.toString(nRadix); // See if there's an approprate prefix of either 0x or 0. // Optionally, the prefix may be specified as a third parameter. var sPrefix:String = ""; if(nRadix == 16) { sPrefix = "0x"; } if(nRadix == 8) { sPrefix = "0"; } // If a prefix is specified, use that instead. if(arguments[2] != undefined) { sPrefix = arguments[2]; } // Return the formatted number as a string. return sPrefix + sNumber.toUpperCase(); } var sNumber:String; var sDecimal:String = ","; var sGroup:String = "."; // Check to see if the second parameter is a symbols object. if(arguments[1].group != undefined) { var oSymbols:Object = arguments[1]; } else { // If the second parameter was not the radix and not a symbols // object, then it's a locale. var lLocale:Locale = Locale(arguments[1]); // If the locale is undefined, create a new locale with default settings. if(lLocale == undefined) { lLocale = new Locale(); } var lStyle:Locale = Locale(lLocale); // Get the symbols for the formatting based on the locale - includes grouping, // decimal, etc. var oSymbols:Object = getSymbols(false, lStyle); } sDecimal = oSymbols.decimal; sGroup = oSymbols.group; // Split the number into two arrays of characters. var aParts:Array = String(nNumber).split("."); var aPart0:Array = aParts[0].split(""); var aPart1:Array = aParts[1].split(""); // If the mask is not defined, then use default formatting. if(_sMask == undefined) { var nCounter:Number = 1; aPart0.reverse(); // Loop through the characters of the first array in reverse order. // Every third number add a grouping symbol. for(var i:Number = 0; i < aPart0.length; i++) { if(nCounter > 3) { nCounter = 0; aPart0.splice(i, 0, sGroup); } nCounter++; } aPart0.reverse(); // Join the characters back to a string, then concatenate the decimal symbol // and the second part of the number. sNumber = aPart0.join(""); if(aParts[1] != undefined) { sNumber += sDecimal + aParts[1]; } } else { // Otherwise, the mask was specified, so use it to format the number. // Split the mask into arrays of characters. var aMask:Array = _sMask.split(""); for(var i:Number = 0; i < aMask.length; i++) { if(aMask[i] != "0" && aMask[i] != "#" && aMask[i] != ".") { aMask.splice(i, 1); i--; } } aMask = aMask.join("").split("."); var aMask0:Array = aMask[0].split(""); var aMask1:Array = aMask[1].split(""); var nCounter:Number = aMask0.length; var nPart0Index:Number = 0; var nMaskIndex:Number = 0; sNumber = ""; // If nCounter is less than the length of the first part of the number string, // then that means that several characters of the first part of the number string // need to get added to the return string before dealing with the mask. if(nCounter < aPart0.length) { for(var i:Number = 0; i < aPart0.length - nCounter; i++) { sNumber += aPart0[i]; nPart0Index++; } } else if(nCounter > aPart0.length) { // Otherwise, if the number of mask character is greater than the digit in the number, // Add leading zeros or spaces. for(var i:Number = 0; i < nCounter - aPart0.length; i++) { if(aMask0[i] == "0") { sNumber += "0"; } else if (aMask0[i] == "#") { sNumber += " "; } nMaskIndex++; } } var bNumeric:Boolean = false; // Loop through each of the remaining characters in the mask. for(var i:Number = nMaskIndex; i < aMask0.length; i++) { // If the mask character is anything other than a # or 0, and no other // numeric character has yet been encountered, then use a space. Otherwise // if it's a 0 or # add the number, and if it's a comma add the grouping // symbol. if(aMask0[i] == "0" || aMask0[i] == "#") { sNumber += (aPart0[nPart0Index] == undefined) ? "" : aPart0[nPart0Index]; nPart0Index++; } } // Split the mask string into an array using the dot as the // delimiter. Then split the first element of that array into an array // of characters. aMask = _sMask.split("."); aMask = aMask[0].split(""); // Split the number string into an array of characters. var aNumber:Array = sNumber.split(""); // Declare a variable and initialize it to false. This variable is // to keep track of whether or not a numeric value has been encountered // yet. var bNumeric:Boolean = false; // Loop through each element of the array of mask characters. for(var i:Number = 0; i < aMask.length; i++) { // Check to see if the element of the mask is one of the special // mask characters. if(aMask[i] != "0" && aMask[i] != "#" && aMask[i] != ".") { // If a numeric character has been encountered then add a grouping // symbol to the number. Otherwise add a space. if(bNumeric) { aNumber.splice(i, 0, sGroup); } else { aNumber.splice(i, 0, " "); } } // Check to see if the current character is numeric (and non-zero). if(aNumber[i] != " " && aNumber[i] != "0") { bNumeric = true; } } // Join the characters in the array back to a string. sNumber = aNumber.join(""); // If there's a second part to the mask, then append the decimal // symbol to the number. if(aMask1 != undefined) { sNumber += sDecimal; } var nDigits:Number; // Loop through each element of the second mask part. for(var i:Number = 0; i < aMask1.length; i++) { // Check to see if the character in the second number part is // defined. if(aPart1[i] == undefined) { // If the character is undefined then append either a 0 or a space // if the corresponding character in the mask array is either 0 or // a #. if(aMask1[i] == "0") { sNumber += "0"; } else if(aMask1[i] == "#") { sNumber += " "; } } else { // Otherwise, the character in the number array is defined, so // append the number to the number string. If it happens to be the // last element in the mask string then round the next two digits. // Otherwise, just append the next digit. nDigits = Number(aPart1[i] + "" + aPart1[i + 1]); if(i == aMask1.length - 1 && !isNaN(nDigits)) { sNumber += String(Math.round(nDigits/10)); } else { sNumber += aPart1[i]; } } } } // Return the number string. return sNumber; } /** * Format a number as currency. This method works very similarly to the * standard format( ) method. *

* Example usage:
* trace(nfFormatter.currencyFormat(1000)); // Displays $1,000.00
* trace(nfFormatter.currencyFormat(1000, new Locale("fr"))); // Displays: 1.000,00€
* trace(nfFormatter.currencyFormat(1000, {group: "|", decimal: "%", before: true, currency: "^"})); // Displays: ^1|000%00
*

* to the nearest of a specified interval. * @param number The number you want to format. * @param locale (optional) A Locale object. * @param symbols object (optional) An object specifying the group, decimal, and currency symbols. * Can also include a before (Boolean) property specifying whether or not * ths currency symbol should be placed at the beginning or end. * @return The formatted number as a string. */ public function currencyFormat(nAmount:Number):String { // If the locale is passed to the method, use that. Otherwise, create a new, // default Locale object. var lStyle:Locale = (arguments[1] instanceof Locale) ? arguments[1] : new Locale(); // If the symbols object is passed to the method, use that. Otherwise, retrieve // the symbols object based on the locale. if(arguments[1].group != undefined) { var oSymbols:Object = arguments[1]; } else { var oSymbols:Object = getSymbols(true, lStyle); } var sCurrencySymbol:String = oSymbols.currency; var sGroup:String = oSymbols.group; var sDecimal:String = oSymbols.decimal; var sTempMask:String = _sMask; _sMask = null; // Create a Locale object that uses US formatting, then format the // amount using that locale. var lLocale:Locale = new Locale(); lLocale.language = "en"; lLocale.variant = "US"; var sAmount:String = format(nAmount, lLocale); _sMask = sTempMask; // Split the formatter string into parts using the dot as the // delimiter. var aParts:Array = sAmount.split("."); // If there were no decimal places, use a default of 00. Otherwise, // Round the decimal places to two. if(aParts[1] == undefined) { aParts[1] = "00"; } else { aParts[1] = Number(aParts[1]); var nPart1Length:Number = String(aParts[1]).length; if(nPart1Length > 2) { aParts[1] /= Math.pow(10, (nPart1Length - 2)); aParts[1] = Math.round(aParts[1]); } } // Join the parts pack to a new string. Then split that into an array // of characters. sAmount = aParts.join("."); var aAmount:Array = sAmount.split(""); // Loop through each of the elements of the array, and replace commas // with the appropriate grouping symbol and dots with the appropriate // decimal marker. for(var i:Number = 0; i < aAmount.length; i++) { if(aAmount[i] == ",") { aAmount[i] = sGroup; } else if(aAmount[i] == ".") { aAmount[i] = sDecimal; } } // Add the current symbol. var sReturnString:String = ((oSymbols.before) ? sCurrencySymbol : "") + aAmount.join("") + ((!oSymbols.before) ? sCurrencySymbol : ""); // Return the string. return sReturnString; } /** * Parse a string to a number. Numbers can be parsed using localized * settings. *

* Example usage:
* trace(nfFormatter.currencyFormat(1000)); // Displays $1,000.00
* trace(nfFormatter.currencyFormat(1000, new Locale("fr"))); // Displays: 1.000,00€
* trace(nfFormatter.currencyFormat(1000, {group: "|", decimal: "%", before: true, currency: "^"})); // Displays: ^1|000%00
*

* to the nearest of a specified interval. * @param number The number string you want to parse. * @param radix (optional) The radix to use when parsing the string. 10 is the default. * @param currency (optional) A Boolean indicating whether or not the number string is formatted * as currency. The default is false. * @param locale (optional) A Locale object. * @return The number. */ public function parse(sNumber:String, nRadix:Number, bCurrency:Boolean, lStyle:Locale):Number { // If the locale parameter is unspecified, use a default Locale object. if(lStyle == undefined) { lStyle = new Locale(); } // Get the symbols. var oSymbols:Object = getSymbols(bCurrency, lStyle); // Split the string into an array of characters. var aCharacters:Array = sNumber.split(""); // If the radix is undefined then use default radix interpretation. if(nRadix == undefined) { // If the first two characters are 0x, use a radix of 16. If the // first character is 0, use a radix of 8. If the first character // is a # then use a radix of 16. Otherwise use the default radix of // 10. if(aCharacters[0] == "O") { if(aCharacters[1] == "x") { nRadix = 16; } else { nRadix = 8; } } else if(aCharacters[0] == "#") { nRadix = 16; } else { nRadix = (nRadix == undefined) ? 10 : nRadix; } } // Loop through each character. If the character is a digit, don't do anything. // If the character is a decimal point, replace it with a dot. If the radix // Is greater than 10, allow alphabetic characters to remain. Otherwise, remove // the character from the array. for(var i:Number = 0; i < aCharacters.length; i++) { switch(aCharacters[i]) { case "0": case "1": case "2": case "3": case "4": case "5": case "6": case "7": case "8": case "9": break; case oSymbols.decimal: aCharacters[i] = "."; break; default: if(nRadix > 10) { if((aCharacters[i].charCodeAt(0) > 64 && aCharacters[i].charCodeAt(0) < 91) || (aCharacters[i].charCodeAt(0) > 96 && aCharacters[i].charCodeAt(0) < 123)) { break; } } aCharacters.splice(i, 1); i--; } } // If the radix is 10, simply return the array of characters joined and // cast as a number. Otherwise, use parseInt( ). if(nRadix == 10) { return Number(aCharacters.join("")); } else { return parseInt(aCharacters.join(""), nRadix); } } // This method is used to retreive grouping, decimal, and currency symbols // based on the locale. private function getSymbols(bCurrency:Boolean, lStyle:Locale):Object { var oSymbols:Object = new Object(); switch(lStyle.languageVariant) { case "en-US": oSymbols.currency = "$"; oSymbols.group = ","; oSymbols.decimal = "."; oSymbols.before = true; break; case "en-UK": oSymbols.currency = "\u00A3"; oSymbols.group = ","; oSymbols.decimal = "."; oSymbols.before = true; break; case "es-MX": oSymbols.currency = "$"; oSymbols.group = ","; oSymbols.decimal = "."; oSymbols.before = true; break; case "es-ES": oSymbols.currency = "\u20AC"; oSymbols.group = "."; oSymbols.decimal = ","; oSymbols.before = false; break; case "fr": oSymbols.currency = "\u20AC"; oSymbols.group = "."; oSymbols.decimal = ","; oSymbols.before = false; break; case "sv": oSymbols.currency = "kr"; oSymbols.group = bCurrency ? "," : " "; oSymbols.decimal = "."; oSymbols.before = false; break; case "jp": oSymbols.currency = "\u200A5"; oSymbols.group = ","; oSymbols.decimal = "."; oSymbols.before = true; break; case "nl": oSymbols.currency = "€"; oSymbols.group = "."; oSymbols.decimal = ","; oSymbols.before = true; break; default: oSymbols.currency = "\u20AC"; oSymbols.group = "."; oSymbols.decimal = ","; oSymbols.before = true; break; } return oSymbols; } }