Skip to content

Instantly share code, notes, and snippets.

@somarlyonks
Created June 11, 2019 07:00
Show Gist options
  • Select an option

  • Save somarlyonks/a154ab30ae32ce0909025c47df0fbcf3 to your computer and use it in GitHub Desktop.

Select an option

Save somarlyonks/a154ab30ae32ce0909025c47df0fbcf3 to your computer and use it in GitHub Desktop.
123 -> 一二三 -> 壹贰叁
const decimalism = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九']
const scalar = ['', '十', '百', '千']
const modular = 10000
const modualrScalar = ['', '万', '亿', '万']
function _123To壹贰叁 (num) {
if (isNaN(num)) return 'NaN'
if (num === 0) return '零'
if (num >= 1000000000000) return 'NaN' // 会计用兆而不是万亿,懒得转换了
const DECIMALISM = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖']
const SCALAR = ['', '拾', '佰', '仟']
const UNIT = ['角', '分', '厘', '毫']
// const SCALARS = modualrScalar.map(_ => [_].concat(SCALAR.slice(-3))).flat()
const yYeEsSMap = {
'负': '(负数)'
}
decimalism.forEach((_, i) => yYeEsSMap[decimalism[i]] = DECIMALISM[i])
scalar.forEach((_, i) => yYeEsSMap[scalar[i]] = SCALAR[i])
const integer = _123To一二三(parseInt(num))
const decimal = num.toFixed(2).split('.')[1]
const yuan = integer.split('').map(x => yYeEsSMap[x] || x).join('') + '圆'
const fen = !parseInt(decimal[1]) ? '' : DECIMALISM[decimal[1]] + UNIT[1]
const jiaofen = decimal === '00' ? '' : DECIMALISM[decimal[0]] + UNIT[0] + (fen || '整')
return yuan + (jiaofen || '整')
}
/**
* @description 另有一种写法
* Math.abs(num)
* .toString().split('')
* .reduce((r, c, i) => decimalism[digits[digits.length - 1 - i]] + scalars[i] + r, '')
* .replace(/零(千|百|十)/g, '零')
* .replace(/十零/g, '十').replace(/零+/g, '零')
* .replace(/零亿/g, '亿').replace(/零万/g, '万').replace(/亿万/g, '亿')
* .replace(/零+$/, '')
* .replace(/^一十/, '十')
* 为什么不用这个看上去要更简便的方式呢?
* 原因在于这样写非常局限,而且很难实现“一百万零五千”这种转换
*
* 下面的写法更灵活,更易于 transform(返回blocks的话就能进行更多操作),也因此能够更严谨
*/
function _123To一二三 (num) {
if (isNaN(num)) return 'NaN'
if (num % 1) return 'NaN'
if (num > Number.MAX_SAFE_INTEGER) return 'NaN'
if (num === 0) return '零'
const sign = num < 0 ? '负' : ''
num = Math.abs(num)
if (num === 1) return sign + '一'
const blocksCount = Math.ceil(Math.log2(num) / Math.log2(modular))
const yiersan = Array.from({length: blocksCount}, (_, i) => Math.floor(num / modular ** i) % modular)
.reverse()
.map(block => block.toString())
.map((block, i, blocks) =>
(!i ? '' : block.length !== 4 || blocks[i - 1].endsWith('0') ? '零' : '') +
// (block.length !== 4 && i ? '零' : '') +
block.split('')
.map(x => parseInt(x))
.map((x, i) => decimalism[x] + (x ? scalar[block.length - i - 1] : ''))
.join('')
.replace(/零+/, '零').replace(/零+$/, '')
)
.map((block, i) => block + modualrScalar[blocksCount - i - 1])
.join('')
.replace(/^一十/, '十')
return sign + yiersan
}
const usecases = [
[1000, '一千'],
[1001, '一千零一'],
[1011, '一千零一十一'],
[1101, '一千一百零一'],
[11000, '一万一千'],
[11001, '一万一千零一'],
[101001, '十万零一千零一']
]
function test (f, u) {
const e = u[1]
console.log('EXPECTED:', e)
const r = f(u[0])
console[r === e ? 'info' : 'error']('GOT :', r)
}
function tests (f, us) {
us.forEach(u => test(f, u))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment