UNPKG

shuzi

Version:

Chinese Number Format | 中文数字格式

145 lines (144 loc) 4.82 kB
const SCRIPTS = { 'zh-CN-small': '零一二三四五六七八九十百千万亿点负元整角分厘毫', 'zh-CN-big': '零壹贰叁肆伍陆柒捌玖拾佰仟万亿点负元整角分厘毫', 'zh-HK-small': '零一二三四五六七八九十百千萬億點負元整角分厘毫', 'zh-HK-big': '零壹貳參肆伍陸柒捌玖拾佰仟萬億點負圓整角分厘毫', 'zh-TW-small': '零一二三四五六七八九十百千萬億點負元整角分厘毫', 'zh-TW-big': '零壹貳參肆伍陸柒捌玖拾佰仟萬億點負圓整角分厘毫', }; export class NumberFormat { constructor(locale, options) { this.locale = locale; this.options = options; this.script = SCRIPTS[locale]; this.intl = new Intl.NumberFormat('en-US', { style: 'decimal', maximumFractionDigits: options?.maximumFractionDigits || (options?.style === 'currency' ? 2 : 3), useGrouping: false, }); } format(value) { if (!this._validate(value)) { return 'InvalidNumber'; } const num = Number(value); const [significant, fragment] = this.intl.format(Math.abs(num)).split('.'); let output = this._formatSignificant(significant); if (this.options?.style === 'currency') { if (significant === '0' && fragment) { // 大于零元,小于一元的情况 output = ''; } else { // 「元」 output += this.script[17]; } if (fragment) { // 「角、分、厘、毫」 output += this._formatFragmentCurrency(fragment, significant); } else { // 「整」 output += this.script[18]; } } else if (fragment) { // 「点」 output += this.script[15] + this._formatFragment(fragment); } // 「负」 if (num < 0) { output = this.script[16] + output; } return output; } /** * 整数部分格式化 */ _formatSignificant(value) { // 「零」简化处理 if (value === '0') { return this.script[0]; } // 四位以内简化处理 if (value.length <= 4) { return this._formatSignificantGroup(value); } let output = ''; for (let i = 0; i < value.length / 4; i++) { switch (i) { // 「万」 case 3: case 1: output = this.script[13] + output; break; // 「亿」 case 2: output = this.script[14] + output; break; default: break; } output = this._formatSignificantGroup(value.substring(value.length - (i + 1) * 4, value.length - i * 4)) + output; } return output; } /** * 整数部分四位一组格式化 */ _formatSignificantGroup(value) { let output = ''; for (let i = 0; i < value.length; i++) { const digit = Number(value[value.length - 1 - i]); // 合并连续的「零」,移除末尾的「零」 if (digit === 0 && (!output || output[0] === this.script[0])) { continue; } // 「十、百、千」 if (i > 0 && digit !== 0) { output = this.script[i + 9] + output; } output = this.script[digit] + output; } return output; } /** * 小数部分格式化 */ _formatFragment(value) { let output = ''; for (let i = 0; i < value.length; i++) { const digit = Number(value[i]); output += this.script[digit]; } return output; } /** * 金额小数部分格式化 */ _formatFragmentCurrency(value, significant) { let output = ''; for (let i = 0; i < value.length; i++) { const digit = Number(value[i]); if (digit === 0) { // 合并连续的「零」,移除开头的「零」 if (output.endsWith(this.script[0]) || (significant === '0' && !output)) { continue; } output += this.script[0]; } else { output += this.script[digit] + this.script[19 + i]; } } return output; } /** * 校验数字是否有效 */ _validate(value) { const num = Number(value); return !Number.isNaN(num) && Number.isFinite(num); } }