惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

A
About on SuperTechFans
博客园 - 聂微东
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园 - 司徒正美
宝玉的分享
宝玉的分享
美团技术团队
量子位
The Cloudflare Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
IT之家
IT之家
爱范儿
爱范儿
J
Java Code Geeks
博客园 - Franky
Last Week in AI
Last Week in AI
B
Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
I
InfoQ
GbyAI
GbyAI
Recent Announcements
Recent Announcements
小众软件
小众软件
H
Help Net Security
Microsoft Azure Blog
Microsoft Azure Blog
MyScale Blog
MyScale Blog

博客园 - 草率的龙果果

window 11 Ultra5‑125H,Arrow Lake 卡顿解决办法 npm配置内网,git配置内网 jenkins打包完镜像更新页面没有变化 vue2 element ui dialog拖拽功能实现。 AI整理提示词 前端数据导出excel工具函数 自动监测数据有效传输率统计算法说明 echarts官方扩展vue组件vue-echarts实现链接两个charts实现联动 OPPO商店签名认领应用 iframe跨域通信(postMessage) 博文阅读密码验证 - 博客园 项目常用工具函数获取url参数和hash参数 Copilot键怎么改成Ctrl键? plus.downloader.createDownload 发送 POST 请求并携带 token vue2,vue3中在template中使用component组件is属性绑定jsx的vnode vue3 vite idea中control+鼠标单击不能跳转到文件定义的解决办法 vue/html-self-closing Vue2项目解决van-calendar 显示白色空白,需滑动一下屏幕,才可正常显示 Windows Terminal/Powershell 设置自动补全, 智能提示 【类似于mac的iterm2功能】 vue中使用axios获取不到响应头Content-Disposition的解决办法 ES7 新增方法:Array.prototype.some、Array.prototype.every 博文阅读密码验证 - 博客园 vue2使用openlayers10.3.0版本组包 javascript跨域问题排查
数字转换为中文数字
草率的龙果果 · 2026-04-24 · via 博客园 - 草率的龙果果

/**
 * 数字转换为中文数字
 * @param {number|string} num 需要转换的数字
 * @param {object} options 配置项
 * @param {boolean} options.uppercase 是否使用大写中文数字(壹贰叁...),默认 false
 * @returns {string} 中文数字字符串
 * @example
 * numberToChinese(0)        // '零'
 * numberToChinese(10)       // '十'
 * numberToChinese(12)       // '十二'
 * numberToChinese(123)      // '一百二十三'
 * numberToChinese(1001)     // '一千零一'
 * numberToChinese(10000)    // '一万'
 * numberToChinese(100010000) // '一亿零一万'
 * numberToChinese(110)      // '一百一十'
 * numberToChinese(123, { uppercase: true }) // '壹佰贰拾叁'
 */
export function numberToChinese(num, options = {}) {
	const { uppercase = false } = options

	// 数字字符映射
	const digits = uppercase
		? ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖']
		: ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九']

	// 量级映射
	const units = uppercase ? ['', '拾', '佰', '仟'] : ['', '十', '百', '千']
	const bigUnits = ['', '万', '亿', '万亿']

	const n = Math.floor(Number(num))
	if (isNaN(n)) return ''
	if (n === 0) return digits[0]

	let neg = false
	let absNum = n

	if (absNum < 0) {
		neg = true
		absNum = Math.abs(absNum)
	}

	// 将数字按4位一段从低到高拆分
	const segments = []
	while (absNum > 0) {
		segments.push(absNum % 10000)
		absNum = Math.floor(absNum / 10000)
	}

	let result = ''
	let needZero = false // 标记是否需要在下一段前补"零"(段间零)

	for (let s = segments.length - 1; s >= 0; s--) {
		const segment = segments[s]
		if (segment === 0) {
			needZero = true
			continue
		}

		// 段间零:上一段为0或标记需要零
		if (needZero || (s < segments.length - 1 && segment < 1000)) {
			result += digits[0]
			needZero = false
		}

		// 从高位到低位处理4位数
		let hasNonZero = false
		for (let i = 3; i >= 0; i--) {
			const divisor = Math.pow(10, i)
			const d = Math.floor(segment / divisor) % 10
			if (d === 0) {
				if (hasNonZero) {
					// 中间零:前面有非零数字,后面可能还有非零数字
					// 先标记,等遇到下一个非零数字时再输出"零"
					needZero = true
				}
			} else {
				if (needZero) {
					result += digits[0]
					needZero = false
				}
				result += digits[d] + units[i]
				hasNonZero = true
			}
		}

		// 添加大单位(万、亿)
		result += bigUnits[s]
		needZero = false
	}

	// 最高位"一十"省略为"十"
	const prefix = uppercase ? '壹拾' : '一十'
	if (result.startsWith(prefix)) {
		result = result.slice(1)
	}

	return (neg ? '负' : '') + result
}