UNPKG

number-reads-cn

Version:

数字中文读法转换工具(电话读法、数值读法、序列读法、金额读法、大写读法)

195 lines (171 loc) 5.11 kB
const digitToChineseMap: Record<string, string> = { '0': '零', '1': '一', '2': '二', '3': '三', '4': '四', '5': '五', '6': '六', '7': '七', '8': '八', '9': '九', } const digitToPhoneMap: Record<string, string> = { '0': '零', '1': '夭', '2': '二', '3': '三', '4': '四', '5': '五', '6': '六', '7': '七', '8': '八', '9': '九', } const digitToUppercaseMap: Record<string, string> = { '0': '零', '1': '壹', '2': '贰', '3': '叁', '4': '肆', '5': '伍', '6': '陆', '7': '柒', '8': '捌', '9': '玖', } /** * 数值中文大写(金额式读法)—— 支持亿以内 */ const numberToChineseValue = (numStr: string) => { const num = Number(numStr) if (isNaN(num)) return numStr const digitToChinese = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九'] const unit = ['', '十', '百', '千'] const sectionUnit = ['', '万', '亿', '兆'] const toSection = (sectionNum: string) => { let str = '' let zero = true const sectionArr = sectionNum.split('').reverse() for (let i = 0; i < sectionArr.length; i++) { const n = parseInt(sectionArr[i]) if (n === 0) { if (!zero) { zero = true str = digitToChinese[0] + str } } else { zero = false str = digitToChinese[n] + unit[i] + str } } return str.replace(/零+$/g, '') } const numArr = numStr.split('').reverse().join('').match(/.{1,4}/g) || [] let result = '' for (let i = 0; i < numArr.length; i++) { const section = toSection(numArr[i].split('').reverse().join('')) if (section !== '') { result = section + sectionUnit[i] + result } else { if (!result.startsWith('零')) result = '零' + result } } result = result.replace(/^一十/, '十') result = result.replace(/零+/g, '零') result = result.replace(/零+$/g, '') return result } /** * 获取所有中文数字读法 */ export const getAllNumberReads = (input: string): { label: string; value: string }[] => { const phoneRead = input .split('') .map(char => digitToPhoneMap[char] || char) const phoneSegments = [ phoneRead.slice(0, 3).join(''), phoneRead.slice(3, 7).join(''), phoneRead.slice(7).join(''), ] const telephone = phoneSegments.filter(s => s).join(' ') const number = numberToChineseValue(input) const currency = number + '元' const sequence = input .split('') .map(char => digitToChineseMap[char] || char) .join(' ') const upper = input .split('') .map(char => digitToUppercaseMap[char] || char) .join('') return [ { label: '电话读法', value: telephone }, { label: '数值读法', value: number }, { label: '金额读法', value: currency }, { label: '序列读法', value: sequence }, { label: '大写读法', value: upper }, ] } /** * 将中文数字读法(如:一百八十六)反向转为数字(如:186) * 暂只支持简体数字读法,不支持金额/大写/序列等 */ export const chineseToNumber = (chinese: string): number | null => { const charToDigit: Record<string, number> = { '零': 0, '一': 1, '二': 2, '三': 3, '四': 4, '五': 5, '六': 6, '七': 7, '八': 8, '九': 9 } const unitMap: Record<string, number> = { '十': 10, '百': 100, '千': 1000, '万': 10000, '亿': 100000000 } let result = 0 let section = 0 let number = 0 let unit = 1 for (let i = chinese.length - 1; i >= 0; i--) { const char = chinese[i] if (char in charToDigit) { number = charToDigit[char] if (unit > 1) { section += number * unit unit = 1 } else { section += number } } else if (char in unitMap) { unit = unitMap[char] if (unit >= 10000) { result += section * unit section = 0 } } else { // 忽略非数字字符 } } result += section return isNaN(result) ? null : result } /** * 支持 getAllNumberReads 返回的所有读法反向转为数字 */ export const chineseReadToNumber = (read: string): number | null => { // 去除空格和单位 const cleanRead = read.replace(/[元\s]/g, '') // 如果是序列或电话读法(逐个数字中文) if (/^[零一二三四五六七八九夭]+$/.test(cleanRead)) { const map: Record<string, string> = { '夭': '1', '零': '0', '一': '1', '二': '2', '三': '3', '四': '4', '五': '5', '六': '6', '七': '7', '八': '8', '九': '9' } return Number(cleanRead.split('').map(c => map[c] || '').join('')) || null } // 如果是大写读法(壹贰叁) if (/^[壹贰叁肆伍陆柒捌玖零]+$/.test(cleanRead)) { const map: Record<string, string> = { '壹': '1', '贰': '2', '叁': '3', '肆': '4', '伍': '5', '陆': '6', '柒': '7', '捌': '8', '玖': '9', '零': '0' } return Number(cleanRead.split('').map(c => map[c] || '').join('')) || null } // 否则用中文数值解析(如 一百八十六) return chineseToNumber(cleanRead) }