Skip to content

Instantly share code, notes, and snippets.

@tonyc726
Created December 24, 2015 11:45
Show Gist options
  • Star 32 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save tonyc726/00c829a54a40cf80409f to your computer and use it in GitHub Desktop.
Save tonyc726/00c829a54a40cf80409f to your computer and use it in GitHub Desktop.
JS数字金额大写转换
var digitUppercase = function(n) {
var fraction = ['角', '分'];
var digit = [
'零', '壹', '贰', '叁', '肆',
'伍', '陆', '柒', '捌', '玖'
];
var unit = [
['元', '万', '亿'],
['', '拾', '佰', '仟']
];
var head = n < 0 ? '欠' : '';
n = Math.abs(n);
var s = '';
for (var i = 0; i < fraction.length; i++) {
s += (digit[Math.floor(n * 10 * Math.pow(10, i)) % 10] + fraction[i]).replace(/零./, '');
}
s = s || '整';
n = Math.floor(n);
for (var i = 0; i < unit[0].length && n > 0; i++) {
var p = '';
for (var j = 0; j < unit[1].length && n > 0; j++) {
p = digit[n % 10] + unit[1][j] + p;
n = Math.floor(n / 10);
}
s = p.replace(/(零.)*零$/, '').replace(/^$/, '零') + unit[0][i] + s;
}
return head + s.replace(/(零.)*零元/, '元')
.replace(/(零.)+/g, '零')
.replace(/^整$/, '零元整');
};
console.log(digitUppercase(7682.01)); //柒仟陆佰捌拾贰元壹分
console.log(digitUppercase(7682)); //柒仟陆佰捌拾贰元整
console.log(digitUppercase(951434677682.00)); //玖仟伍佰壹拾肆亿叁仟肆佰陆拾柒万柒仟陆佰捌拾贰元整
@hzq1988a
Copy link

做了一个移位的优化,防止出现精度不准的问题

var digitUppercase = function(n) {
    var fraction = ['角', '分'];
    var digit = [
        '零', '壹', '贰', '叁', '肆',
        '伍', '陆', '柒', '捌', '玖'
    ];
    var unit = [
        ['元', '万', '亿'],
        ['', '拾', '佰', '仟']
    ];
    var head = n < 0 ? '欠' : '';
    n = Math.abs(n);
    var s = '';
    for (var i = 0; i < fraction.length; i++) {
        s += (digit[Math.floor(shiftRight(n,1+i)) % 10] + fraction[i]).replace(/零./, '');
    }
    s = s || '整';
    n = Math.floor(n);
    for (var i = 0; i < unit[0].length && n > 0; i++) {
        var p = '';
        for (var j = 0; j < unit[1].length && n > 0; j++) {
            p = digit[n % 10] + unit[1][j] + p;
            n = Math.floor(shiftLeft(n, 1));
        }
        s = p.replace(/(零.)*零$/, '').replace(/^$/, '零') + unit[0][i] + s;
    }
    return head + s.replace(/(零.)*零元/, '元')
        .replace(/(零.)+/g, '零')
        .replace(/^整$/, '零元整');
};
 
console.log(digitUppercase(100111));
console.log(digitUppercase(7.52));  
console.log(digitUppercase(951434677682.00));

// 向右移位
function shiftRight(number, digit){
    digit = parseInt(digit, 10);
    var value = number.toString().split('e');
    return +(value[0] + 'e' + (value[1] ? (+value[1] + digit) : digit))
}
// 向左移位
function shiftLeft(number, digit){
    digit = parseInt(digit, 10);
    var value = number.toString().split('e');
    return +(value[0] + 'e' + (value[1] ? (+value[1] - digit) : -digit))
}
`

@ishowshao
Copy link

100个赞

@jszjgqq
Copy link

jszjgqq commented Oct 22, 2018

标准的财务数字大写,如果是负数的话应该这么写:

比如 -1.00

大写: (负数)壹元整

代码优化如下:

var head = n < 0 ? '欠' : '(负数)';

// 对数字先进行判断 不然有可能出现undefined角undefined分的情况
if (!/^(-)?(0|[1-9]\d*)(.\d+)?$/.test(n))
return "数据非法";

@y1324
Copy link

y1324 commented Oct 26, 2018

标准的财务数字大写,如果是负数的话应该这么写:

比如-1.00

大写:(负数)壹元整

代码优化如下:

var head = n <0?'欠':'(负数)';

//对数字先进行判断不然有可能出现undefined角undefined分的情况
if(!/ ^( - )?(0 | [1-9] \ d *)(。\ d +)?$ / .test(n ))
返回“数据非法”;

var head = n <0?'欠':'(负数)';

这个优化的,好像也不对吧。如果是正数的话,是直接在前面加(负数)了啊。
不是应该
var head = n <0?'(负数)':'';
这样的吗?(如有不对,请指正。)

@hwlv
Copy link

hwlv commented Apr 23, 2019

超出千亿的可以支持下吗

@wangyangyangyang
Copy link

还会涉及到一个精度计算的问题

@tonyc726
Copy link
Author

tonyc726 commented Apr 1, 2021

还会涉及到一个精度计算的问题

本来是写报销单的时候用的,没考虑这么多,请问精度问题会出现在哪些情况呢?

@volunteer1024
Copy link

volunteer1024 commented Aug 24, 2021

还会涉及到一个精度计算的问题

本来是写报销单的时候用的,没考虑这么多,请问精度问题会出现在哪些情况呢?

今天遇到一个测试用例就是 34.01,粗略测了一下,三十几开头的,零壹分,都会被展示成三十几圆整
image

@tonyc726
Copy link
Author

@volunteer1024 精度问题,依据 @hzq1988a 的方案改动后已经解决;

// 向右移位
function shiftRight(number, digit) {
  digit = parseInt(digit, 10);
  var value = number.toString().split('e');
  return +(value[0] + 'e' + (value[1] ? +value[1] + digit : digit));
}
// 向左移位
function shiftLeft(number, digit) {
  digit = parseInt(digit, 10);
  var value = number.toString().split('e');
  return +(value[0] + 'e' + (value[1] ? +value[1] - digit : -digit));
}

var digitUppercase = function (n) {
  var fraction = ['角', '分'];
  var digit = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'];
  var unit = [
    ['元', '万', '亿'],
    ['', '拾', '佰', '仟'],
  ];
  var head = n < 0 ? '欠' : '';
  n = Math.abs(n);
  var s = '';
  for (var i = 0; i < fraction.length; i++) {
    s += (digit[Math.floor(shiftRight(n, 1 + i)) % 10] + fraction[i]).replace(
      /零./,
      ''
    );
  }
  s = s || '整';
  n = Math.floor(n);
  for (var i = 0; i < unit[0].length && n > 0; i++) {
    var p = '';
    for (var j = 0; j < unit[1].length && n > 0; j++) {
      p = digit[n % 10] + unit[1][j] + p;
      n = Math.floor(shiftLeft(n, 1));
    }
    s = p.replace(/(零.)*零$/, '').replace(/^$/, '零') + unit[0][i] + s;
  }
  return (
    head +
    s
      .replace(/(零.)*零元/, '元')
      .replace(/(零.)+/g, '零')
      .replace(/^整$/, '零元整')
  );
};

console.log(digitUppercase(30.01)); // > 叁拾元壹分

@legend80s
Copy link

能否来一个单测,否则有些case很难覆盖

@Siykt
Copy link

Siykt commented Nov 10, 2023

看看我的,测试用例在这里,这是参考税务局的实现,差异主要在 1.01 -> 壹元零壹分

/**
 * 将阿拉伯数字价格转换为中文价格
 * @param price 阿拉伯数字价格
 * @returns 中文价格
 */
export function getChinesePrice(price: number) {
  if (price === 0) return '零元整'
  if (price >= 1e12) return '整数位已超过最大值'

  const CHINESE_NUMBER_MAP = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖']
  const CHINESE_UNIT_MAP = ['', '拾', '佰', '仟']
  const CHINESE_BIG_UNIT_MAP = ['', '万', '亿']
  const CHINESE_SMALL_UNIT_MAP = ['角', '分', '厘', '毫']

  const priceStr = price.toString()
  const priceArr = priceStr.split('.')
  const integer = priceArr[0]
  const decimal = priceArr[1]

  let chineseIntegerPrice = ''
  let zeroCount = 0

  for (let i = 0; i < integer.length; i++) {
    const num = +integer[i]
    const unit = integer.length - i - 1 // 当前数字的单位
    const quotient = Math.floor(unit / 4) // 1w为进位单位, 除 4 即为 万 亿
    const remainder = unit % 4 // 1w为进位单位, 取模 4 即为 个 十 百 千

    if (num === 0) {
      zeroCount++
    } else {
      // 处理前置的零
      if (zeroCount > 0) chineseIntegerPrice += CHINESE_NUMBER_MAP[0]
      zeroCount = 0
      chineseIntegerPrice += CHINESE_NUMBER_MAP[num] + CHINESE_UNIT_MAP[remainder]
    }
    if (remainder === 0 && zeroCount < 4) {
      chineseIntegerPrice += CHINESE_BIG_UNIT_MAP[quotient]
    }
  }

  // 价格为小数时,整数部分不显示
  if (price < 1) chineseIntegerPrice = ''
  else chineseIntegerPrice += '元'

  let chineseDecimalPrice = ''

  if (!decimal) {
    chineseDecimalPrice = '整'
  } else {
    let hasZero = false
    for (let i = 0; i < decimal.length; i++) {
      const num = +decimal[i]
      if (num) chineseDecimalPrice += CHINESE_NUMBER_MAP[num] + CHINESE_SMALL_UNIT_MAP[i]
      else hasZero = true
    }

    if (chineseIntegerPrice && hasZero) chineseIntegerPrice += '零'
  }

  return chineseIntegerPrice + chineseDecimalPrice
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment