import { checkBoundary } from '../utils/math.util';
// 简体
const chnNumberChar = ["零", "一", "二", "三", "四", "五", "六", "七", "八", "九"];
const chnUnitChar = ["", "十", "百", "千"];
// 繁体
const big5NumberChar = ["零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"];
const big5UnitChar = ["", "拾", "佰", "仟"];
// 数字字符、计数单位
let numberChar, unitChar, unitSection;
/**
* 每个小节的内部进行转化
*
* @private
* @param {Number} section 数字
* @returns {String} 转化的数字
*/
function sectionToChinese(section) {
let str = '',
chnstr = '',
zero = false, //zero为是否进行补零, 第一次进行取余由于为个位数,默认不补零
unitPos = 0;
while (section > 0) {
// 对数字取余10,得到的数即为个位数
let v = section % 10;
//如果数字为零,则对字符串进行补零
if (v == 0) {
if (zero) {
//如果遇到连续多次取余都是0,那么只需补一个零即可
zero = false;
chnstr = numberChar[v] + chnstr;
}
} else {
//第一次取余之后,如果再次取余为零,则需要补零
zero = true;
str = numberChar[v];
str += unitChar[unitPos];
chnstr = str + chnstr;
}
unitPos++;
section = Math.floor(section / 10);
}
return chnstr;
}
/**
* 转换整数
*
* @private
* @param {Number} num 要转换的数字
* @returns {String} 中文数字
*/
function convertInteger(num) {
num = Math.floor(num);
let unitPos = 0;
let strIns = '', chnStr = '';
let needZero = false;
if (num === 0) {
return numberChar[0];
}
while (num > 0) {
var section = num % 10000;
if (needZero) {
chnStr = numberChar[0] + chnStr;
}
strIns = sectionToChinese(section);
strIns += (section !== 0) ? unitSection[unitPos] : unitSection[0];
chnStr = strIns + chnStr;
needZero = (section < 1000) && (section > 0);
num = Math.floor(num / 10000);
unitPos++;
}
return chnStr;
}
/**
* 转换小数
*
* @private
* @param {Number} num 要转换的数字
*/
function convertDecimal(num) {
const numStr = num + '';
const index = numStr.indexOf(".");
let ret = '';
if (index > -1) {
let decimalStr = numStr.slice(index + 1);
ret = mapNumberChar(parseInt(decimalStr));
}
return ret;
}
/**
* 映射为中文数字
*
* @private
* @param {Number} num 要处理的数字
* @returns {String} 返回中文数字的映射
*/
function mapNumberChar(num) {
const numStr = num + '';
let ret = '';
for (let i = 0, len = numStr.length; i < len; i++) {
ret += numberChar[parseInt(numStr[i])];
}
return ret;
}
/**
* 数字转中文数字
* 不在安全数字 -9007199254740991~9007199254740991 内,处理会有异常
*
* @static
* @alias module:Processor.numberToChinese
* @since 1.2.0
* @param {Number} num 数字
* @param {Object} [options] 配置项
* @param {Boolean} [options.big5=false] 繁体
* @param {Boolean} [options.unit=true] 计数单位
* @param {String} [options.decomal=点] 中文小数点
* @param {String} [options.zero=零] 设置0。常用配置 〇
* @param {String} [options.negative=负] 负数前面的字
* @param {Object} [options.unitConfig] 节点单位配置
* @param {String} [options.unitConfig.w=万] 设置计数单位万。常用配置 萬
* @param {String} [options.unitConfig.y=亿] 设置计数单位亿。常用配置 億
* @returns {String} 中文数字
* @example
*
* numberToChinese(100);
* // => 一百
*
* numberToChinese(100.3);
* // => 一百点三
*
* // 繁体
* numberToChinese(100, {big5: true});
* // => 壹佰
*
* numberToChinese(100.3, {big5: true});
* // => 壹佰点叁
*
* numberToChinese(1234567890, {big5: true});
* // => 壹拾贰亿叁仟肆佰伍拾陆万柒仟捌佰玖拾
*
* // 不带计数单位
* numberToChinese(1990, {unit: false});
* // => 一九九零
*
* // 不带计数单位,修改0
* numberToChinese(1990, {unit: false, zero:'〇'});
* // => 一九九〇
*
*/
function numberToChinese(num, {
big5 = false,
unit = true,
decimal = '点',
zero = '',
negative = '负',
unitConfig = {
w: '万', // '萬'
y: '亿' // '億'
}
} = {}) {
// 非数字 或 NaN 不处理
if (typeof num !== 'number' || isNaN(num)) {
console.warn(`参数错误 ${num},请传入数字`);
return '';
}
// 超过安全数字提示
checkBoundary(num);
// 设置数字字符和计数单位
if (big5) {
numberChar = big5NumberChar.slice();
unitChar = big5UnitChar.slice();
} else {
numberChar = chnNumberChar.slice();
unitChar = chnUnitChar.slice();
}
// 设置节点计数单位,万、亿、万亿
unitSection = ['', unitConfig.w, unitConfig.y, unitConfig.w + unitConfig.y];
// 设置0
if (zero) {
numberChar[0] = zero;
}
// 前置字符,负数处理
const preStr = num < 0 ? negative : '';
// 整数和小数
let chnInteger, chnDecimal;
// 处理整数
if (unit) {
chnInteger = convertInteger(num);
} else {
chnInteger = mapNumberChar(Math.floor(num));
}
// 处理小数
chnDecimal = convertDecimal(num);
return chnDecimal ? `${preStr}${chnInteger}${decimal}${chnDecimal}` : `${preStr}${chnInteger}`;
}
export default numberToChinese;