【JS Utils】formatNumber 格式化数字 (支持高精度、去科学计数法、控制大小范围、整数补零、补充千分位符号)

formatNumber(格式化数字)

  • 简述:用于格式化数字文本或类数字的值,支持高精度计算、去科学计数法、控制大小范围、整数补零、补充千分位符号、进制基数转换 (开发中)。
  • 兼容:最低需支持 ES6 环境,补零或高精度计算时需支持 ES7 环境,BigInt 类型数值运算时需支持 ES10 环境。
  • 特性:此方法执行运算的时间复杂度在 O(n) 内,执行效率较优,适合作为通用工具函数使用。

源码

/**
 *  格式化数字
 *  @description  支持高精度格式化,可去除科学计数法,精度保留至无限
 *  @param  {*}       value                   输入源
 *  @param  {Object}  [options]               配置项
 *  @param  {Number}  [options.min]           最小值
 *  @param  {Number}  [options.max]           最大值
 *  @param  {Number}  [options.precision]     数字精度 (结果保留的浮点位数)
 *  @param  {Number}  [options.sumPrecision]  算术精度 (计算结果的实际精度)
 *  @param  {*}       [options.defaultValue]  数字无效时的默认值
 *  @param  {Boolean} [options.defaultMinMax] 默认值是否使用最小值或最大值 ( true: 默认值,存在最小或最大值时默认使用 | false: 不使用 )
 *  @param  {Number}  [options.zeroFill]      是否补零 ( 默认不补零 | Number: 自定义长度补零 )
 *  @param  {Boolean} [options.milFill]       是否补充千分位符号 ( 默认值不使用 | true: 使用 )
 *  @return {String}
 */
function formatNumber(value, options) {
  let { min, max, precision, sumPrecision, defaultMinMax = true, zeroFill, milFill } = options || {}
  let result = value, defaultValue = options && 'defaultValue' in options ? options.defaultValue : ''
  if (!(
    (typeof result == 'number' || typeof result == 'string' && result !== '') && !isNaN(result) ||
    typeof result == 'bigint' && (result = String(result))
  )) return defaultValue
  if (min != null && result < +min) {
    if (!defaultMinMax) return defaultValue; result = min
  } else if (max != null && result > +max) {
    if (!defaultMinMax) return defaultValue; result = max
  }
  if (!isFinite(result)) return defaultValue
  if (/0(b|o|x)/i.test(result)) result = String((typeof BigInt == 'function' ? BigInt : Number)(result))
  if (sumPrecision != null && (precision == null || precision > sumPrecision)) result = numToFixed(result, sumPrecision)
  result = numToFixed(result, precision)
  if (zeroFill > 0 || milFill) {
    let { 1: minus = '', 2: int = '', 3: any = '' } = /^(-?)(\d+)(.*)/.exec(result) || {}
    if (zeroFill > int.length) int = `${''.padEnd(zeroFill - int.length, 0)}${int}`
    if (milFill) {
      let r = '', s = 3, i = int.length
      while ((i -= s) > -s) r = `${int.slice(i > 0 ? i : 0, i + s)}${r ? ',' : ''}${r}`
      int = r
    }
    result = `${minus}${int}${any}`
  }
  return result
}

/**
 *  高精度小数取舍
 *  @param  {Number}  value       输入源
 *  @param  {Number}  [precision] 数字精度 (可保留的浮点位数,为空时仅精度化不进行取舍)
 *  @return {String}
 */
function numToFixed(value, precision) {
  if (!isFinite(value)) return String(+value)
  let reg = /^(-?)0*(\d*)(\.?)(\d*?)0*(e(-|\+)?(\d+))?$/i
  let { 1: minus = '', 2: int = '', 4: dec = '', 6: dir, 7: fe } = reg.exec(value) || {}
  if (minus && !(int || dec)) minus = ''
  if (fe > 0 && (int || dec)) {
    if (dir != '-') {
      let df = fe - dec.length
      int = df < 0 ? `${int}${dec.slice(0, df)}` : `${int}${dec}${''.padEnd(df, 0)}`
      dec = df < 0 ? dec.slice(df) : ''
    } else {
      let df = fe - int.length
      dec = df < 0 ? `${int.slice(-df)}${dec}` : `${''.padEnd(df, 0)}${int}${dec}`
      int = df < 0 ? int.slice(0, -df) : ''
    }
  }
  if (precision != null) {
    precision = Math.max(Math.floor(precision), 0) || 0
    if (precision >= dec.length) {
      dec = dec.padEnd(precision, 0)
    } else {
      let grd = dec[precision] > 4; dec = dec.slice(0, precision)
      if (grd) {
        let r = '', b = `${int || 0}${dec}`, d = dec.length, i = b.length
        while (--i >= 0) {
          if (b[i] < 9) {
            r = `${b.slice(0, i)}${+b[i] + 1}${r}`; break
          } else {
            r = `${i == 0 ? '1' : ''}0${r}`
          }
        }
        int = d ? r.slice(0, -d) : r
        dec = d ? r.slice(-d) : ''
      }
    }
  }
  return `${minus}${int || 0}${dec ? `.${dec}` : ''}`
}

使用示例

formatNumber(), formatNumber(''), formatNumber('abc'), formatNumber(null)
// => ''
formatNumber(123)
// => '123'
formatNumber(123n)
// => '123'
formatNumber('123.00')
// => '123'
formatNumber('0b0101010')
// => '42'
formatNumber('0o1234567')
// => '342391'
formatNumber('0x1234abc')
// => '19090108'
formatNumber('-00123.45e+5')
// => '-12345000'
formatNumber('123.45000e-5')
// => '0.0012345'
formatNumber('123.45600', { precision: 2 })
// => '123.46'
formatNumber('123.45678', { precision: 3, min: 100, max: '110.50' })
// => '110.500'
formatNumber('abc', { defaultValue: null })
// => null
formatNumber(100, { min: 150, max: 200, defaultValue: 'abc', defaultMinMax: true })
// => '150'
formatNumber(300, { min: 150, max: 200, defaultValue: 'abc', defaultMinMax: false })
// => 'abc'
formatNumber('123.456', { zeroFill: 10 })
// => '0000000123.456'
formatNumber('12345678901234.56789', { milFill: true })
// => '12,345,678,901,234.56789'
String(Number('0.00000010200'))
// => '1.02e-7'
formatNumber('0.00000010200')
// => '0.000000102'
String(Number('0x1234567890abcdf123'))
// => '335812727627494300000'
formatNumber('0x1234567890abcdf123')
// => '335812727627494322467'
String(Number('12345.678901234567890'))
// => '12345.678901234567'
formatNumber('12345.678901234567890')
// => '12345.67890123456789'
String(Number('12345.678901234567890').toFixed(20))
// => '12345.67890123456709261518'
formatNumber('12345.678901234567890', { precision: 20 })
// => '12345.67890123456789000000'
String(Number('12345.678901234567890e30').toFixed(4))
// => '1.234567890123457e+34'
formatNumber('12345.678901234567890e30', { precision: 4 })
// => '12345678901234567890000000000000000.0000'
formatNumber('-12345.6789012345678901234567890e19', { zeroFill: 28, milFill: true })
// => '-0,000,123,456,789,012,345,678,901,234.56789'
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值