Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[js] 第114天 写一个把数字转成中文的方法,例如:101转成一百零一 #1039

Open
haizhilin2013 opened this issue Aug 7, 2019 · 18 comments
Labels
js JavaScript

Comments

@haizhilin2013
Copy link
Collaborator

第114天 写一个把数字转成中文的方法,例如:101转成一百零一

@haizhilin2013 haizhilin2013 added the js JavaScript label Aug 7, 2019
@ghost
Copy link

ghost commented Aug 8, 2019

const digitChar = ['', ...'一二三四五六七八九']
const posChar = ['', ...'十百千万   亿']
const placeholder = '零'

function toChineseNumeralUnder万(digits) {
    let revDigits = digits.split('').reverse()
    let result = ''
    for (let pos = 0; pos < revDigits.length; pos++) {
        const digit = Number(revDigits[pos])
        if (digit)
            { result = posChar[pos] + result }
        if (digit !== 1 || pos !== 1)
            { result = digitChar[digit] + result }
        if (!digit && pos && result && !result.startsWith(placeholder))
            { result = placeholder + result }
    }
    return result
}

function toChineseNumeralUnder亿(digits) {
    let highPart = toChineseNumeralUnder万(digits.slice(-8, -4))
    if (highPart)
        { highPart += posChar[4] }
    let lowPart = toChineseNumeralUnder万(digits.slice(-4))
    return highPart + lowPart
}

function toChineseNumeral(digits) {
    let fragment = ''
    const result = []
    for (const digit of digits.split('').reverse()) {
        if (fragment.length === 8) {
            result.unshift(toChineseNumeralUnder亿(fragment))
            fragment = ''
        }
        fragment = digit + fragment
    }
    result.unshift(toChineseNumeralUnder亿(fragment))
    if (result[0].startsWith(placeholder))
        { result[0] = result[0].slice(1) }
    return result.join(posChar[8]) || placeholder
}
toChineseNumeral('0')
// => '零'
toChineseNumeral('101')
// => '一百零一'
toChineseNumeral('1000001')
// => '一百万零一'
toChineseNumeral('123456708')
// => '一亿二千三百四十五万六千七百零八'
toChineseNumeral('3274823947329471041041234567080')
// => '三百二十七万四千八百二十三亿九千四百七十三万二千九百四十七亿一千零四十一万零四百一十二亿三千四百五十六万七千零八十'

函数名很弱智,不要在意(

@haizhilin2013
Copy link
Collaborator Author

@t532 这函数名中英文结合呢,不错不错!

@ghost
Copy link

ghost commented Aug 8, 2019

@NicholasBaiYa

你好,
你的实现似乎有一些问题?
下面是我尝试的结果:

numToChinese('121')
// => '壹贰拾壹百'
numToChinese('12147238372')
// => '壹亿贰壹undefined肆千柒拾贰拾叁百捌千叁万柒百贰undefined'

@NicholasBaiYa
Copy link

@NicholasBaiYa

你好,
你的实现似乎有一些问题?
下面是我尝试的结果:

numToChinese('121')
// => '壹贰拾壹百'
numToChinese('12147238372')
// => '壹亿贰壹undefined肆千柒拾贰拾叁百捌千叁万柒百贰undefined'

唔~我在改改··位数只写到亿,下钟后在改改,感谢大佬指教

@liuxiaole
Copy link

liuxiaole commented Aug 8, 2019

@NicholasBaiYa
你好,
你的实现似乎有一些问题?
下面是我尝试的结果:

numToChinese('121')
// => '壹贰拾壹百'
numToChinese('12147238372')
// => '壹亿贰壹undefined肆千柒拾贰拾叁百捌千叁万柒百贰undefined'

唔~我在改改··位数只写到亿,下钟后在改改,感谢大佬指教

toChineseNumeral('1000001'); // expected: 一百万零一
// actual: 一百零万零一

@ghost
Copy link

ghost commented Aug 8, 2019

@liuxiaole

toChineseNumeral('1000001'); // expected: 一百万零一
// actual: 一百零万零一

试着修了一下,现在可以了。

@DarthVaderrr
Copy link

/*
 * @param {Number} 数字 
 * @return {String} 中文数字
 * 
*/
var arg = process.argv.slice(2)[0] + '';//node命令参数

console.log(CN_Number(arg));

function CN_Number(num) {
    let str = num + '';
    let arr = [];
    let res = [];
    for (let i = str.length-1; i >=0; i -= 4) {
        arr.unshift(str.slice(i-4, i))
    }
    while (arr.length) {
        res.unshift(arr.splice(-3, 3))
    }

    let block=['亿','万',''];
    res = res.map(item =>{
       if(item.length<3) item.unshift('');
       return item.map((n,index) => {
            let res = cn_fy(n);
            res+=res?block[index]:"";
            return res;
        })
    });
    let cn_res='';
    res.forEach((a)=>{
        a.forEach(b=>{
            cn_res+=b;
        })
    })
    return  cn_res
    function cn_fy(n) {
        let unit = ['千', '百', '十'];
        let nums = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九'];
        let res = '';
        for (let i = 0; i < n.length; ++i) {
            if (n[i] == 0) res += '零'
            else res += nums[n[i]] + (unit[i] || '')
        }
        while(res[0]==='零'){
            res=res.substring(1)
        }//去左零
        while(res[res.length-1]==='零'){
            res=res.substring(0,res.length-1)
        }//去右零
        while(res.indexOf('零零')>-1){
            res=res.replace('零','')
        }//去连续零
        return res;
    }
}

@liuxiaole
Copy link

liuxiaole commented Aug 9, 2019

function toChineseNumeral(n) {
    let units = ['', '十', '百', '千'];
    let numbers = '零一二三四五六七八九'.split('');
    let alternateTwo = '两';

    /**
    * 按 length 把 str 切割,然后每段由 callback 来处理
    * 后用 unit 连接,同时处理段之间要不要加零
    */
    let fragmentFactory = (length, unit, callback) => {
        let fn = strNum => {
            if(strNum.length === 0) return '';
            let tail = strNum.substring(strNum.length - length, strNum.length);
            let head = strNum.substring(0, strNum.length - length);
            let headResolved = fn(head);
            if (headResolved.length > 0) {
                headResolved += unit;
                if (tail.match(/^0+[1-9]/)) {
                    headResolved += numbers[0];
                }
            }
            return headResolved + callback(tail.replace(/^0+/, ''));
        };
        return fn;
    }

    /**
    * 处理万以内的数字
    */
    let resolve4 = partition => {
        let digits = partition.split('');
        let retStr = '';
        for(let i = 0; i < digits.length; i++) {
            let d = digits[i];
            if(d === '0') continue;

            if(i >= 1 && digits[i-1] === '0') {
                retStr += numbers[0];
            }

            let unit = digits.length - i - 1;
            let isTwoThousand = d === '2' && unit === 3;
            retStr += (isTwoThousand ? alternateTwo : numbers[d]) + units[unit];
        }
        return retStr;
    };

    // 先以 8 位切,然后以 4位切
    let fragment4 = fragmentFactory(4, '万', resolve4);
    let fragment8 = fragmentFactory(8, '亿', fragment4);
    // 要 京 兆 垓 都是没有问题的
   // fragment 16 京, fragment 32 兆 一直写下去就行    

    return fragment8(String(n)) || numbers[0];
}

@forever-z-133
Copy link

forever-z-133 commented Aug 12, 2019

function returnChineseNumber(num, chineseType) {
  if (!num) return '';

  var numArr = [num].toString().split('');
  var _numConfig = '零一二三四五六七八九'.split('');
  var _unitConfig = ' 十百千'.split('');
  var _sizeConfig = ' 万亿兆'.split('');
  if (chineseType) {
    _numConfig = '零壹贰叁肆伍陆柒捌玖'.split('');
    _unitConfig = ' 拾佰仟'.split('');
    // _sizeConfig = ' 萬億兆'.split('');
  }

  var result = '';
  for (var i=0,len=numArr.length; i<len; i++) {
    var n = Number(numArr[len-i-1]);
    var cn = _numConfig[n];
    var unit = i%4 !== 0 ? _unitConfig[i%4] : '';
    var size = i%4 === 0 && i !== 0 ? _sizeConfig[i/4] : '';

    // 现在将返回 1001 => 一千零百零十一,不符合情况,则进行以下处理
    if (cn === '零') unit = '';
    if (cn === '零' && (result === '' || result.slice(0, 1) === '零')) cn = '';

    result = cn + unit + size + result;
  }

  return result;
}
console.log(returnChineseNumber(123123123))
// 一亿二千三百一十二万三千一百二十三

@liuxiaole
Copy link

function returnChineseNumber(num, chineseType) {
  if (!num) return '';

  var numArr = [num].toString().split('');
  var _numConfig = '零一二三四五六七八九'.split('');
  var _unitConfig = ' 十百千'.split('');
  var _sizeConfig = ' 万亿兆'.split('');
  if (chineseType) {
    _numConfig = '零壹贰叁肆伍陆柒捌玖'.split('');
    _unitConfig = ' 拾佰仟'.split('');
    // _sizeConfig = ' 萬億兆'.split('');
  }

  var result = '';
  for (var i=0,len=numArr.length; i<len; i++) {
    var cn = _numConfig[numArr[len-i-1]];
    var unit = _unitConfig[i%4];
    var size = i%4 === 0 ? _sizeConfig[i/4] : '';
    if (unit === ' ') unit = '';
    if (size === ' ') size = '';
    if (cn === '零') unit = '';
    result = cn + unit + size + result;
  }
  
  return result;
}
console.log(returnChineseNumber(123123123))
// 一亿二千三百一十二万三千一百二十三

returnChineseNumber(201001);
// 预期: 二十万一千零一
// 实际: 二十零万一千零零一
returnChineseNumber(1000000);
// 预期: 一百万
//实际:一百零零万零零零零

@liuxiaole
Copy link

liuxiaole commented Aug 12, 2019

@liuxiaole

toChineseNumeral('1000001'); // expected: 一百万零一
// actual: 一百零万零一

试着修了一下,现在可以了。

toChineseNumeral('1110');
// expected 一千一百一十
// actual 一千一百十
‘一十’ 只有在小于20才可以读作“十”或“十几”,所以干脆直接留下“一十”这种情况,或者判断“一十”是否为开头

@forever-z-133
Copy link

returnChineseNumber(201001);
// 预期: 二十万一千零一
// 实际: 二十零万一千零零一
returnChineseNumber(1000000);
// 预期: 一百万
//实际:一百零零万零零零零

感谢,代码已更新。

@jiamianmao
Copy link

jiamianmao commented Aug 13, 2019

import nzh from 'nzh/cn'

nzh.encodeS(n)

不好意思,搞定了,泡妞去了。

@jiamianmao
Copy link

jiamianmao commented Aug 14, 2019

    function formatChineseTypeNumber(number) {
      const digitChar = [...'零一二三四五六七八九']
      const posChar = ['', ...'十百千']
      const unit = ['', '万', '亿']

      let str = ''
      let arr = number.replace(/(\d{1,4})(?=(?:\d{4})+(?!\d))/g,'$1,').split(',')

      const formatWan = (number, unit) => {
        let string = ''
        number.split('').forEach((x, i) => {
          if (x !== '0') {
            let posCharIndex = number.length - i - 1
            // 处理 `一十万` 改为 `十万`
            if (x === '1' && posCharIndex === 1) {
              string += `${posChar[posCharIndex]}`
            } else {
              string += `${digitChar[x]}${posChar[posCharIndex]}`
            }
          } else if (string.slice(-1) !== '零') {
            string += '零'
          }
        })
        while(string.slice(-1) === '零') {
          string = string.slice(0, -1)
        }
        return string && `${string}${unit}`
      }

      arr.forEach((item, index) => {
        str += formatWan(item, `${unit[arr.length - index - 1]}`)
      })
      return str
    }

    formatChineseTypeNumber('10000') // 一万
    formatChineseTypeNumber('1000') // 十万
    formatChineseTypeNumber('1000000') // 一百万

@wiseal2
Copy link

wiseal2 commented Oct 30, 2019

function transformNumber(number) {
		const mapping = {
			100000000: '亿',
			10000000: '千万',
			1000000: '百万',
			100000: '十万',
			10000: '万',
			1000: '千',
			100: '百',
			10: '十',
			0: '零',
			1: '一',
			2: '二',
			3: '三',
			4: '四',
			5: '五',
			6: '六',
			7: '七',
			8: '八',
			9: '九'
		}
		const keys = Object.keys(mapping).sort((a, b) => b - a);
		let retStr = '', temp = number, tempStr;
		for (let k of keys) {
			tempStr = ~~(temp / k);
			temp = temp % k;
			if (tempStr) {
				retStr += `${mapping[tempStr]}${mapping[k]}`;
			} else if (mapping[k] === '十' && tempStr === 1) {
				retStr += '一十'; // 特殊处理 10 读作 一十
			} else if (!tempStr && retStr && retStr[retStr.length - 1] !== '零') {
				retStr += '零';
			} else if (temp < 10) {
				if (temp !== 0) { // 特殊处理末尾 0
					retStr += mapping[temp]
				}
				break; // 已到达个位数,退出循环
			}
			if (!temp) break;
		}
		console.log(retStr);
	}
	transformNumber(10101101) // 一千万零一十万零一千一百零一

@creasy2010
Copy link

/**
 * @desc
 *
 * @使用场景
 *
 * @coder.yang2010@gmail.com
 * @Date    2019/12/5
 **/

var unit = ['', '十', '百', '千'];
var segmentUnit = ['', '万', '亿','兆'];
var number = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九'];

function transfer(digits: number, unitIndex = 0) {
  // let segment = digits % 10000;
  // let result = digits / 10000;

  let segmentResults = [];

  let currentSegment;
  let nextVal=digits;
  do {
    currentSegment = nextVal % 10000;

    nextVal = Math.floor(nextVal / 10000);

    if (currentSegment > 0) {
      segmentResults.push((nextVal>0?"零":"")+
        transferSegment(currentSegment, segmentUnit[unitIndex++]),
      );
    }

  } while (nextVal > 0);

  return segmentResults.reverse().join('');
}

function transferSegment(segment: number, segmentUnit: string): string {
  let result = [];
  let currentValue = segment;
  let _unitIndex = 0;

  let  isLastZero= null;

  do {
    let current = currentValue % 10;
    currentValue = Math.trunc(currentValue / 10);
    let _unit =  unit[_unitIndex++];
    if (current !== 0) {
      result.push( number[current] + _unit,
      );
      isLastZero = false;
    } else {
      if(isLastZero===false){
        result.push(
          "零",
        );
      }
      isLastZero = true;
    }
  } while (currentValue > 0);



  return result.reverse().join("") + segmentUnit;
}

console.log(transfer(1000));
console.log(transfer(1001));
console.log(transfer(1011));
console.log(transfer(1111));
console.log(transfer(9999));
console.log(transfer(19999));
console.log(transfer(1000999));

@canwdev
Copy link

canwdev commented Mar 8, 2020

function translateNumber(num) {
  var numStr = Math.round(num).toString().split('')
  if (numStr.length > 12) {
    throw '数字超过最大范围:千亿'
  }
  var digitChar = ['', '一', '二', '三', '四', '五', '六', '七', '八', '九']
  var posChar = ['', '十', '百', '千', '万', '十', '百', '千', '亿', '十', '百', '千']
  var zeroChar = '零'
  var lastChar
  var result = numStr.map((char, index) => {
    var pos = numStr.length - 1 - index
    var res = digitChar[char]
    if (char === '0') {
      if (lastChar && lastChar !== zeroChar) { // 避免重复的零
        if (pos === 4 || pos === 8) { // 处理万和亿
          res += posChar[pos]
        } else {
          res += zeroChar
        }
      }
    } else {
      res += posChar[pos]
    }
    lastChar = digitChar[char]
    return res
  })
  result = result.filter(i => i) // 去除空白数组项
  if (result.lastIndexOf(zeroChar) === result.length - 1) { // 删除最后的零
    result.pop()
  }
  return result.join('')
}
console.log(translateNumber(5)) // 五
console.log(translateNumber(20))  // 二十
console.log(translateNumber(100)) // 一百
console.log(translateNumber(105)) // 一百零五
console.log(translateNumber(111)) // 一百一十一
console.log(translateNumber(256)) // 二百五十六
console.log(translateNumber(1024))  // 一千零二十四
console.log(translateNumber(10086)) // 一万零八十六
console.log(translateNumber(10001)) // 一万零一
console.log(translateNumber(101010))  // 一十万一千零一十
console.log(translateNumber(2050100)) // 二百零五万零一百
console.log(translateNumber(10101101))  // 一千零一十万一千一百零一
console.log(translateNumber(909090909001))  // 九千零九十亿九千零九十万九千零一

@wind8866
Copy link

wind8866 commented Mar 25, 2022

比我想的要难多了,思路是四个一组,为了与字典相匹配,倒序倒序再倒序。兼容性挺好的,支持 BigInt、小数、支持科学表示法的数字

// 支持 BigInt、小数、支持科学表示法的数字
const num2cn = (num) => {
  const numDic = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九']
  const siteDic = ['千', '百', '十', '']
  const groupDic = ['', '万', '亿', '兆', '京', '垓', '秭', '穰', '沟', '涧', '正', '载', '🐶']
  const numStr = num.toLocaleString().replaceAll(',', '')
  const [intArr, dicimalArr] = numStr.split('.').map(str => str.split(''))
  const dicimalResult = dicimalArr ? '点' + dicimalArr.map(val => numDic[val]).join('') : ''
  let groupInt = []
  intArr.reverse().forEach((val, index) => {// 倒叙是为了 intArr 的数组下标与 groupDic 相对应
    if (index % 4 === 0) groupInt.push(new Array(4).fill('0'))
    groupInt[Math.floor(index / 4)][3 - index % 4] = val// 每一组也做了倒叙,与 siteDic 相对应
  })
  groupInt = groupInt
    .map((arr, i) => {
      // 每一组的值加上 siteDic 的单位
      return arr.map((value, j) => {
        if (value === '0') {
          return numDic[value]
        }
        return numDic[value] + siteDic[j]
      })
    })
    .reverse()// 组倒序
    .reduce((str, arr, groupIndex, allArr) => {
      const groupKey = groupDic[allArr.length - 1 - groupIndex]
      return str + arr.reduce((before, current, currentIndex) => {
        return before + current + (currentIndex === 3 ? groupKey : '')// 加上 groupDic 单位
      }, '')
    }, '')
    // 去除各种多余的零
  groupInt = groupInt.replace(/(?<=零)[零万亿兆京垓秭穰沟涧正载🐶]+|^零+|零+$/g, '') + dicimalResult
  return groupInt
}
console.log(13, num2cn(13))
console.log(130000, num2cn(130000))
console.log(130000.4334, num2cn(13_0000.4334))
console.log(100_0000_0030, num2cn(100_0000_0030))
console.log(10_0000_0000_0000_0030n, num2cn(1_0000_0000_0000_0030n))
console.log(11_1111_1111_1111_1131n, num2cn(1_1111_1111_1111_1131n))
console.log(1010_1101, num2cn(1010_1101))
console.log(9090_9090_9001, num2cn(9090_9090_9001))
console.log(327_4823_9473_2947_1041_0412_3456_7080n, num2cn(327_4823_9473_2947_1041_0412_3456_7080n))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
js JavaScript
Projects
None yet
Development

No branches or pull requests

10 participants