formatCurrency
ts
/**
* 将数字格式化为货币字符串。
*
* @param {number} num - 要格式化的数字。
* @param {number} [unit=100] - 将数字除以的单位(例如,100表示从分到元)。
* @param {string} [symbol='¥'] - 前缀的货币符号。
* @param {number} [digits=2] - 显示的小数位数。
* @param {function} [parser] - 可选的解析函数,用于在格式化之前处理数值。
* @returns {string} 格式化后的货币字符串。
*/
export const formatCurrency = function (
num: number,
unit: number = 100,
symbol: string = '¥',
digits: number = 2,
parser?: (value: number) => number
): string {
// 规范化输入数字,默认为0如果未定义或为null
const normalizedNum = num ?? 0
// 按指定单位除以数字
let value = normalizedNum / unit
// 如果提供了解析函数,则应用它
if (isFunction(parser)) {
value = parser(value)
}
// 确定符号位置
const sign = normalizedNum < 0 ? '-' : ''
// 将值格式化为带有指定符号和小数位数的货币字符串
return `${symbol}${sign}${Math.abs(value).toLocaleString('en-US', {
minimumFractionDigits: digits,
maximumFractionDigits: digits,
})}`
}ts
import { describe, it, expect } from 'vitest'
import { formatCurrency } from '../index'
describe('formatCurrency', () => {
it('1. 应将整数100格式化为"¥1.00"', () => {
expect(formatCurrency(100)).toBe('¥1.00')
})
it('2. 应将负数-100格式化为"¥-1.00"', () => {
expect(formatCurrency(-100)).toBe('¥-1.00')
})
it('3. 应将0格式化为"¥0.00"', () => {
expect(formatCurrency(0)).toBe('¥0.00')
})
it('4. 应使用自定义单位格式化', () => {
expect(formatCurrency(10000, 1000)).toBe('¥10.00')
})
it('5. 应使用自定义货币符号格式化', () => {
expect(formatCurrency(100, 100, '$')).toBe('$1.00')
})
it('6. 应使用自定义小数位数格式化', () => {
expect(formatCurrency(100, 100, '¥', 3)).toBe('¥1.000')
})
it('7. 应使用自定义解析函数格式化', () => {
const parser = (value: number) => value * 2
expect(formatCurrency(100, 100, '¥', 2, parser)).toBe('¥2.00')
})
it('8. 应处理未定义的num', () => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
expect(formatCurrency(undefined)).toBe('¥0.00')
})
it('9. 应处理null值的num', () => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
expect(formatCurrency(null)).toBe('¥0.00')
})
it('10. 应处理负数和自定义解析函数', () => {
const parser = (value: number) => value * 2
expect(formatCurrency(-100, 100, '¥', 2, parser)).toBe('¥-2.00')
})
it('11. 应使用自定义单位和小数位数格式化', () => {
expect(formatCurrency(123456, 100, '€', 0)).toBe('€1,235')
})
})digitUppercase
ts
/**
* 将数字转换为大写金额表示形式的字符串。
* @param {number} n - 要转换的数字,范围为 -9999999999999.99 到 9999999999999.99。
* @returns {string} 转换后的大写金额表示形式的字符串。
*/
export const digitUppercase = (n: number): string => {
const fraction = ['角', '分']
const digit = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖']
const unit = [
['元', '万', '亿'],
['', '拾', '佰', '仟'],
]
const head = n < 0 ? '欠' : ''
n = Math.abs(n)
let s = ''
// Handle fraction part
for (let i = 0; i < fraction.length; i++) {
s += (digit[Math.floor(n * 10 * 10 ** i) % 10] + fraction[i]).replace(/零./, '')
}
s = s || '整'
// Handle integer part
n = Math.floor(n)
for (let k = 0; k < unit[0].length && n > 0; k++) {
let p = ''
for (let 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][k]}${s}`
}
return `${head}${s
.replace(/(零.)*零元/, '元')
.replace(/(零.)+/g, '零')
.replace(/^整$/, '零元整')}`
}ts
import { describe, it, expect } from 'vitest'
import { digitUppercase } from '../index'
describe('digitUppercase', () => {
const testCases: Array<{ input: number; expected: string }> = [
{ input: 123456.78, expected: '壹拾贰万叁仟肆佰伍拾陆元柒角捌分' },
{ input: 100200300, expected: '壹亿零贰拾万零叁佰元整' },
{ input: -987654321.99, expected: '欠玖亿捌仟柒佰陆拾伍万肆仟叁佰贰拾壹元玖角玖分' },
{ input: 0, expected: '零元整' },
{ input: 0.05, expected: '伍分' },
]
testCases.forEach(({ input, expected }, index) => {
it(`case ${index + 1}: ${input} 应转换为 ${expected}`, () => {
expect(digitUppercase(input)).toBe(expected)
})
})
})