zoukankan      html  css  js  c++  java
  • 货币 数字按格式转换

      前段时间,一直在捣鼓着这么把数字形式的金额转换为项目中所需的格式,使用过单纯的js方法,最后在老大的指点下,才发现了另外一种很好用的方法:使用accounting.js。

    accounting.js 是一个非常小的JavaScript方法库用于对数字,金额和货币进行格式化,并提供可选的Excel风格列渲染。它没有依赖任何JS框架。货币符号等可以按需求进行定制。它的代码如下:

      1 /*!
      2  * accounting.js v0.3.2
      3  * Copyright 2011, Joss Crowcroft
      4  *
      5  * Freely distributable under the MIT license.
      6  * Portions of accounting.js are inspired or borrowed from underscore.js
      7  *
      8  * Full details and documentation:
      9  * http://josscrowcroft.github.com/accounting.js/
     10  */
     11 
     12 (function(root, undefined) {
     13 
     14     /* --- Setup --- */
     15 
     16     // Create the local library object, to be exported or referenced globally later
     17     var lib = {};
     18 
     19     // Current version
     20     lib.version = '0.3.2';
     21 
     22 
     23     /* --- Exposed settings --- */
     24 
     25     // The library's settings configuration object. Contains default parameters for
     26     // currency and number formatting
     27     lib.settings = {
     28         currency: {
     29             symbol : "$",        // default currency symbol is '$'
     30             format : "%s%v",    // controls output: %s = symbol, %v = value (can be object, see docs)
     31             decimal : ".",        // decimal point separator
     32             thousand : ",",        // thousands separator
     33             precision : 2,        // decimal places
     34             grouping : 3        // digit grouping (not implemented yet)
     35         },
     36         number: {
     37             precision : 0,        // default precision on numbers is 0
     38             grouping : 3,        // digit grouping (not implemented yet)
     39             thousand : ",",
     40             decimal : "."
     41         }
     42     };
     43 
     44 
     45     /* --- Internal Helper Methods --- */
     46 
     47     // Store reference to possibly-available ECMAScript 5 methods for later
     48     var nativeMap = Array.prototype.map,
     49         nativeIsArray = Array.isArray,
     50         toString = Object.prototype.toString;
     51 
     52     /**
     53      * Tests whether supplied parameter is a string
     54      * from underscore.js
     55      */
     56     function isString(obj) {
     57         return !!(obj === '' || (obj && obj.charCodeAt && obj.substr));
     58     }
     59 
     60     /**
     61      * Tests whether supplied parameter is a string
     62      * from underscore.js, delegates to ECMA5's native Array.isArray
     63      */
     64     function isArray(obj) {
     65         return nativeIsArray ? nativeIsArray(obj) : toString.call(obj) === '[object Array]';
     66     }
     67 
     68     /**
     69      * Tests whether supplied parameter is a true object
     70      */
     71     function isObject(obj) {
     72         return obj && toString.call(obj) === '[object Object]';
     73     }
     74 
     75     /**
     76      * Extends an object with a defaults object, similar to underscore's _.defaults
     77      *
     78      * Used for abstracting parameter handling from API methods
     79      */
     80     function defaults(object, defs) {
     81         var key;
     82         object = object || {};
     83         defs = defs || {};
     84         // Iterate over object non-prototype properties:
     85         for (key in defs) {
     86             if (defs.hasOwnProperty(key)) {
     87                 // Replace values with defaults only if undefined (allow empty/zero values):
     88                 if (object[key] == null) object[key] = defs[key];
     89             }
     90         }
     91         return object;
     92     }
     93 
     94     /**
     95      * Implementation of `Array.map()` for iteration loops
     96      *
     97      * Returns a new Array as a result of calling `iterator` on each array value.
     98      * Defers to native Array.map if available
     99      */
    100     function map(obj, iterator, context) {
    101         var results = [], i, j;
    102 
    103         if (!obj) return results;
    104 
    105         // Use native .map method if it exists:
    106         if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
    107 
    108         // Fallback for native .map:
    109         for (i = 0, j = obj.length; i < j; i++ ) {
    110             results[i] = iterator.call(context, obj[i], i, obj);
    111         }
    112         return results;
    113     }
    114 
    115     /**
    116      * Check and normalise the value of precision (must be positive integer)
    117      */
    118     function checkPrecision(val, base) {
    119         val = Math.round(Math.abs(val));
    120         return isNaN(val)? base : val;
    121     }
    122 
    123 
    124     /**
    125      * Parses a format string or object and returns format obj for use in rendering
    126      *
    127      * `format` is either a string with the default (positive) format, or object
    128      * containing `pos` (required), `neg` and `zero` values (or a function returning
    129      * either a string or object)
    130      *
    131      * Either string or format.pos must contain "%v" (value) to be valid
    132      */
    133     function checkCurrencyFormat(format) {
    134         var defaults = lib.settings.currency.format;
    135 
    136         // Allow function as format parameter (should return string or object):
    137         if ( typeof format === "function" ) format = format();
    138 
    139         // Format can be a string, in which case `value` ("%v") must be present:
    140         if ( isString( format ) && format.match("%v") ) {
    141 
    142             // Create and return positive, negative and zero formats:
    143             return {
    144                 pos : format,
    145                 neg : format.replace("-", "").replace("%v", "-%v"),
    146                 zero : format
    147             };
    148 
    149         // If no format, or object is missing valid positive value, use defaults:
    150         } else if ( !format || !format.pos || !format.pos.match("%v") ) {
    151 
    152             // If defaults is a string, casts it to an object for faster checking next time:
    153             return ( !isString( defaults ) ) ? defaults : lib.settings.currency.format = {
    154                 pos : defaults,
    155                 neg : defaults.replace("%v", "-%v"),
    156                 zero : defaults
    157             };
    158 
    159         }
    160         // Otherwise, assume format was fine:
    161         return format;
    162     }
    163 
    164 
    165     /* --- API Methods --- */
    166 
    167     /**
    168      * Takes a string/array of strings, removes all formatting/cruft and returns the raw float value
    169      * alias: accounting.`parse(string)`
    170      *
    171      * Decimal must be included in the regular expression to match floats (defaults to
    172      * accounting.settings.number.decimal), so if the number uses a non-standard decimal 
    173      * separator, provide it as the second argument.
    174      *
    175      * Also matches bracketed negatives (eg. "$ (1.99)" => -1.99)
    176      *
    177      * Doesn't throw any errors (`NaN`s become 0) but this may change in future
    178      */
    179     var unformat = lib.unformat = lib.parse = function(value, decimal) {
    180         // Recursively unformat arrays:
    181         if (isArray(value)) {
    182             return map(value, function(val) {
    183                 return unformat(val, decimal);
    184             });
    185         }
    186 
    187         // Fails silently (need decent errors):
    188         value = value || 0;
    189 
    190         // Return the value as-is if it's already a number:
    191         if (typeof value === "number") return value;
    192 
    193         // Default decimal point comes from settings, but could be set to eg. "," in opts:
    194         decimal = decimal || lib.settings.number.decimal;
    195 
    196          // Build regex to strip out everything except digits, decimal point and minus sign:
    197         var regex = new RegExp("[^0-9-" + decimal + "]", ["g"]),
    198             unformatted = parseFloat(
    199                 ("" + value)
    200                 .replace(/((.*))/, "-$1") // replace bracketed values with negatives
    201                 .replace(regex, '')         // strip out any cruft
    202                 .replace(decimal, '.')      // make sure decimal point is standard
    203             );
    204 
    205         // This will fail silently which may cause trouble, let's wait and see:
    206         return !isNaN(unformatted) ? unformatted : 0;
    207     };
    208 
    209 
    210     /**
    211      * Implementation of toFixed() that treats floats more like decimals
    212      *
    213      * Fixes binary rounding issues (eg. (0.615).toFixed(2) === "0.61") that present
    214      * problems for accounting- and finance-related software.
    215      */
    216     var toFixed = lib.toFixed = function(value, precision) {
    217         precision = checkPrecision(precision, lib.settings.number.precision);
    218         var power = Math.pow(10, precision);
    219 
    220         // Multiply up by precision, round accurately, then divide and use native toFixed():
    221         return (Math.round(lib.unformat(value) * power) / power).toFixed(precision);
    222     };
    223 
    224 
    225     /**
    226      * Format a number, with comma-separated thousands and custom precision/decimal places
    227      *
    228      * Localise by overriding the precision and thousand / decimal separators
    229      * 2nd parameter `precision` can be an object matching `settings.number`
    230      */
    231     var formatNumber = lib.formatNumber = function(number, precision, thousand, decimal) {
    232         // Resursively format arrays:
    233         if (isArray(number)) {
    234             return map(number, function(val) {
    235                 return formatNumber(val, precision, thousand, decimal);
    236             });
    237         }
    238 
    239         // Clean up number:
    240         number = unformat(number);
    241 
    242         // Build options object from second param (if object) or all params, extending defaults:
    243         var opts = defaults(
    244                 (isObject(precision) ? precision : {
    245                     precision : precision,
    246                     thousand : thousand,
    247                     decimal : decimal
    248                 }),
    249                 lib.settings.number
    250             ),
    251 
    252             // Clean up precision
    253             usePrecision = checkPrecision(opts.precision),
    254 
    255             // Do some calc:
    256             negative = number < 0 ? "-" : "",
    257             base = parseInt(toFixed(Math.abs(number || 0), usePrecision), 10) + "",
    258             mod = base.length > 3 ? base.length % 3 : 0;
    259 
    260         // Format the number:
    261         return negative + (mod ? base.substr(0, mod) + opts.thousand : "") + base.substr(mod).replace(/(d{3})(?=d)/g, "$1" + opts.thousand) + (usePrecision ? opts.decimal + toFixed(Math.abs(number), usePrecision).split('.')[1] : "");
    262     };
    263 
    264 
    265     /**
    266      * Format a number into currency
    267      *
    268      * Usage: accounting.formatMoney(number, symbol, precision, thousandsSep, decimalSep, format)
    269      * defaults: (0, "$", 2, ",", ".", "%s%v")
    270      *
    271      * Localise by overriding the symbol, precision, thousand / decimal separators and format
    272      * Second param can be an object matching `settings.currency` which is the easiest way.
    273      *
    274      * To do: tidy up the parameters
    275      */
    276     var formatMoney = lib.formatMoney = function(number, symbol, precision, thousand, decimal, format) {
    277         // Resursively format arrays:
    278         if (isArray(number)) {
    279             return map(number, function(val){
    280                 return formatMoney(val, symbol, precision, thousand, decimal, format);
    281             });
    282         }
    283 
    284         // Clean up number:
    285         number = unformat(number);
    286 
    287         // Build options object from second param (if object) or all params, extending defaults:
    288         var opts = defaults(
    289                 (isObject(symbol) ? symbol : {
    290                     symbol : symbol,
    291                     precision : precision,
    292                     thousand : thousand,
    293                     decimal : decimal,
    294                     format : format
    295                 }),
    296                 lib.settings.currency
    297             ),
    298 
    299             // Check format (returns object with pos, neg and zero):
    300             formats = checkCurrencyFormat(opts.format),
    301 
    302             // Choose which format to use for this value:
    303             useFormat = number > 0 ? formats.pos : number < 0 ? formats.neg : formats.zero;
    304 
    305         // Return with currency symbol added:
    306         return useFormat.replace('%s', opts.symbol).replace('%v', formatNumber(Math.abs(number), checkPrecision(opts.precision), opts.thousand, opts.decimal));
    307     };
    308 
    309 
    310     /**
    311      * Format a list of numbers into an accounting column, padding with whitespace
    312      * to line up currency symbols, thousand separators and decimals places
    313      *
    314      * List should be an array of numbers
    315      * Second parameter can be an object containing keys that match the params
    316      *
    317      * Returns array of accouting-formatted number strings of same length
    318      *
    319      * NB: `white-space:pre` CSS rule is required on the list container to prevent
    320      * browsers from collapsing the whitespace in the output strings.
    321      */
    322     lib.formatColumn = function(list, symbol, precision, thousand, decimal, format) {
    323         if (!list) return [];
    324 
    325         // Build options object from second param (if object) or all params, extending defaults:
    326         var opts = defaults(
    327                 (isObject(symbol) ? symbol : {
    328                     symbol : symbol,
    329                     precision : precision,
    330                     thousand : thousand,
    331                     decimal : decimal,
    332                     format : format
    333                 }),
    334                 lib.settings.currency
    335             ),
    336 
    337             // Check format (returns object with pos, neg and zero), only need pos for now:
    338             formats = checkCurrencyFormat(opts.format),
    339 
    340             // Whether to pad at start of string or after currency symbol:
    341             padAfterSymbol = formats.pos.indexOf("%s") < formats.pos.indexOf("%v") ? true : false,
    342 
    343             // Store value for the length of the longest string in the column:
    344             maxLength = 0,
    345 
    346             // Format the list according to options, store the length of the longest string:
    347             formatted = map(list, function(val, i) {
    348                 if (isArray(val)) {
    349                     // Recursively format columns if list is a multi-dimensional array:
    350                     return lib.formatColumn(val, opts);
    351                 } else {
    352                     // Clean up the value
    353                     val = unformat(val);
    354 
    355                     // Choose which format to use for this value (pos, neg or zero):
    356                     var useFormat = val > 0 ? formats.pos : val < 0 ? formats.neg : formats.zero,
    357 
    358                         // Format this value, push into formatted list and save the length:
    359                         fVal = useFormat.replace('%s', opts.symbol).replace('%v', formatNumber(Math.abs(val), checkPrecision(opts.precision), opts.thousand, opts.decimal));
    360 
    361                     if (fVal.length > maxLength) maxLength = fVal.length;
    362                     return fVal;
    363                 }
    364             });
    365 
    366         // Pad each number in the list and send back the column of numbers:
    367         return map(formatted, function(val, i) {
    368             // Only if this is a string (not a nested array, which would have already been padded):
    369             if (isString(val) && val.length < maxLength) {
    370                 // Depending on symbol position, pad after symbol or at index 0:
    371                 return padAfterSymbol ? val.replace(opts.symbol, opts.symbol+(new Array(maxLength - val.length + 1).join(" "))) : (new Array(maxLength - val.length + 1).join(" ")) + val;
    372             }
    373             return val;
    374         });
    375     };
    376 
    377 
    378     /* --- Module Definition --- */
    379 
    380     // Export accounting for CommonJS. If being loaded as an AMD module, define it as such.
    381     // Otherwise, just add `accounting` to the global object
    382     if (typeof exports !== 'undefined') {
    383         if (typeof module !== 'undefined' && module.exports) {
    384             exports = module.exports = lib;
    385         }
    386         exports.accounting = lib;
    387     } else if (typeof define === 'function' && define.amd) {
    388         // Return the library as an AMD module:
    389         define([], function() {
    390             return lib;
    391         });
    392     } else {
    393         // Use accounting.noConflict to restore `accounting` back to its original value.
    394         // Returns a reference to the library's `accounting` object;
    395         // e.g. `var numbers = accounting.noConflict();`
    396         lib.noConflict = (function(oldAccounting) {
    397             return function() {
    398                 // Reset the value of the root's `accounting` variable:
    399                 root.accounting = oldAccounting;
    400                 // Delete the noConflict method:
    401                 lib.noConflict = undefined;
    402                 // Return reference to the library to re-assign it:
    403                 return lib;
    404             };
    405         })(root.accounting);
    406 
    407         // Declare `fx` on the root (global/window) object:
    408         root['accounting'] = lib;
    409     }
    410 
    411     // Root will be `window` in browser or `global` on the server:
    412 }(this));
    View Code

      而它的使用则更加方便,只是在项目中引入accounting.js,就可以直接使用了,比如:

    1.formatMoney

    // Default usage:
    accounting.formatMoney(99999999); //$99,999,999.00
    
    // European formatting (custom symbol and separators), could also use options object as second param:
    accounting.formatMoney(4999.99, "€", 2, ".", ","); // €4.999,99
    
    // Negative values are formatted nicely, too:
    accounting.formatMoney(-800000, "£ ", 0); // £ -800,000
    
    // Simple `format` string allows control of symbol position [%v = value, %s = symbol]:
    accounting.formatMoney(999999999, { symbol: "GBP",  format: "%v %s" }); // 999,999,999.00 GBP
    View Code

    2.formatNumber

    accounting.formatNumber(999999999); // 999,999,999
    accounting.formatNumber(9876543.21, 3, " "); // 9 876 543.210
    View Code

    3.unformat

    accounting.unformat("£ 12,345,678.90 GBP"); // 12345678.9
    View Code

    经过自己的实践,觉得这种方法是“金额转换”中最简便的方法,也希望自己以后可以记住,同样可以帮助到其他小伙伴们。

  • 相关阅读:
    pyDNS学习
    BUUCTF password
    攻防世界 easy-apk
    Android Normal writeup
    Jarvis OJ
    阿里云服务器连接(安装)宝塔面板
    bmp格式转为jpeg格式文件
    课设记录-Day15
    课设记录-Day14
    课设记录-Day13
  • 原文地址:https://www.cnblogs.com/zhengyeye/p/5430897.html
Copyright © 2011-2022 走看看