yeojongki / blog

📝
https://blog.iv7n.top/
3 stars 0 forks source link

将数字格式化成金额的形式并四舍五入保留 x 位小数 #10

Open yeojongki opened 5 years ago

yeojongki commented 5 years ago

将数字格式化成金额的形式并四舍五入保留 x 位小数

一. 保留 x 位小数

如: 1234.781 转化为 1,234.78 tofix 存在的问题: JavaScript 浮点数陷阱及解法

另外的办法:Math.round(X * 保留的位数) / 保留的位数

/**
 * 将数字四舍五入保留 x 位小数
 * @param {Number|String} num 传入的数字
 * @param {Number} len 要保留的小数位 如 2 位小数
 * @return {String} result
 * @example handleTail(100.234, 2) -> 100.23
 */
const handleTail = (num, len) => {
  // 扩大相应倍数
  let scale = Math.pow(10, len)
  // 再缩小到原来的倍数
  return Math.round(+num * scale) / scale
}

二. 将数字格式化成金额的形式

/**
 * 将数字格式化成金额的形式
 * @param {Number|String} num 传入的数字(必须是整数!!)
 * @return {String} result
 * @example thoudsandNum(123456) -> 123,456
 */
const thoudsandNum = num => {
  // 判断是否是正数
  let isPosive = true
  if (+num < 0) isPosive = false
  num = Math.abs(num)
  let prefix = isPosive ? '' : '-'
  // 正则相关 https://juejin.im/post/5965943ff265da6c30653879#heading-10
  let ret = ('' + num).replace(/(?!^)(?=(\d{3})+$)/g, ',')
  return prefix + ret
}

三. 分割小数整数部分最终合并

const parseMoney = (num, len = 2) => {
  // 判断输入合法数字
  if (!/^-?\d+$|^(-?\d)+(\.)?\d+$/.test('' + num) || !/^\d+$/.test('' + len)) {
    throw new Error('invalid param `num` or `len`')
  }
  // 取出整数和小数部分
  let [head, tail] = handleTail(num, len).split('.')
  // 处理整数千分位
  head = thoudsandNum(head)
  return `${head}.${tail}`
}

另外还需要处理一些问题:没有小数,或者小数尾数不足的时候补 0

完整代码

/**
 * 将数字格式化成金额的形式并四舍五入保留 x 位小数
 * @param {Number|String} num 传入的数字
 * @param {Number} len 要保留的小数位 (只能是正整数) 如 2 位小数
 * @return {String} result
 * @example parseMoney(-1234564.789) -> -1,234,564.79
 */
const parseMoney = (num, len = 2) => {
  // 判断输入合法数字
  if (!/^-?\d+$|^(-?\d)+(\.)?\d+$/.test('' + num) || !/^\d+$/.test('' + len)) {
    throw new Error('invalid param `num` or `len`')
  }
  // 扩大相应倍数
  let scale = Math.pow(10, len)
  // 再缩小到原来的倍数
  let scaleBack = Math.round(+num * scale) / scale
  // 取出整数和小数部分
  let [head, tail] = ('' + scaleBack).split('.')
  // 补零
  function fillZero(num) {
    let ret = num ? num : ''
    for (let i = 1; i < len; i++) {
      ret += '0'
    }
    return ret
  }
  // 小数尾数补0
  tail = fillZero(tail)
  // 处理整数千分位
  // 处理正负数
  const isPosive = (num == (num = Math.abs(num)))
  head = ('' + Math.abs(head)).replace(/(?!^)(?=(\d{3})+$)/g, ',')
  // 正负号
  let prefix = isPosive ? '' : '-'
  return `${prefix}${head}.${tail}`
}
parseMoney(1234564.789) // 1,234,564.79
parseMoney(1234564.781) // 1,234,564.78
parseMoney(1234564) // 1,234,564.00
parseMoney(-1234564) // -1,234,564.00
parseMoney(-1234564.6) // -1,234,564.60
parseMoney(-1234564.789) // -1,234,564.79
parseMoney(-1234564.6, 4) // -1,234,564.6000
yeojongki commented 4 years ago

补充一种快捷格式化方法:

const num = 123456789
// 格式化千分位输出
num.toLocaleString() // "123,456,789"

// 格式化为千分位带$符号输出
num.toLocaleString("en-US",{style:"currency",currency:"USD"}) // "$123,456,789.00"

// 格式化为带¥符号输出
num.toLocaleString("zh-Hans-CN",{style:"currency",currency:"CNY"}) // "¥123,456,789.00"