实现千位分隔符
将数字格式化为千位分隔符形式,如 1234567 转换为 1,234,567
问题
千位分隔符是一种常见的数字格式化方式,用于提高数字的可读性。需要实现一个函数,将普通数字转换为带有千位分隔符的字符串格式,例如将 1234567.89 转换为 1,234,567.89。
要求支持:
- 整数和小数
- 正数和负数
- 保留小数部分不变
解答
方法一:正则表达式(推荐)
/**
* 使用正则表达式实现千位分隔符
* @param {number|string} num - 需要格式化的数字
* @returns {string} 格式化后的字符串
*/
function formatNumberWithComma(num) {
// 转换为字符串
const str = String(num);
// 分离整数和小数部分
const parts = str.split('.');
// 处理整数部分:使用正则表达式添加千位分隔符
// (?=...) 正向预查,(?!^) 排除开头位置
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
// 拼接整数和小数部分
return parts.join('.');
}
方法二:循环遍历
/**
* 使用循环实现千位分隔符
* @param {number|string} num - 需要格式化的数字
* @returns {string} 格式化后的字符串
*/
function formatNumberWithLoop(num) {
const str = String(num);
const parts = str.split('.');
// 处理整数部分
let integerPart = parts[0];
let result = '';
let count = 0;
// 从右向左遍历
for (let i = integerPart.length - 1; i >= 0; i--) {
count++;
result = integerPart[i] + result;
// 每三位添加逗号,但不在开头添加
if (count % 3 === 0 && i !== 0 && integerPart[i - 1] !== '-') {
result = ',' + result;
}
}
// 拼接小数部分
return parts.length > 1 ? result + '.' + parts[1] : result;
}
方法三:使用 toLocaleString(最简单)
/**
* 使用原生 API 实现千位分隔符
* @param {number} num - 需要格式化的数字
* @returns {string} 格式化后的字符串
*/
function formatNumberWithAPI(num) {
return Number(num).toLocaleString('en-US');
}
方法四:支持负数的完整实现
/**
* 完整的千位分隔符实现(支持负数)
* @param {number|string} num - 需要格式化的数字
* @returns {string} 格式化后的字符串
*/
function formatNumber(num) {
// 处理非法输入
if (num === null || num === undefined || num === '') {
return '';
}
const str = String(num);
// 判断是否为负数
const isNegative = str[0] === '-';
const absoluteStr = isNegative ? str.slice(1) : str;
// 分离整数和小数部分
const parts = absoluteStr.split('.');
// 格式化整数部分
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
// 拼接结果
const result = parts.join('.');
return isNegative ? '-' + result : result;
}
使用示例
// 基本使用
console.log(formatNumber(1234567)); // "1,234,567"
console.log(formatNumber(1234567.89)); // "1,234,567.89"
console.log(formatNumber(-1234567.89)); // "-1,234,567.89"
// 边界情况
console.log(formatNumber(123)); // "123"
console.log(formatNumber(0)); // "0"
console.log(formatNumber(1000)); // "1,000"
console.log(formatNumber(1000000)); // "1,000,000"
// 字符串输入
console.log(formatNumber('9876543210')); // "9,876,543,210"
console.log(formatNumber('123.456789')); // "123.456789"
// 使用原生 API
console.log(formatNumberWithAPI(1234567.89)); // "1,234,567.89"
// 特殊情况
console.log(formatNumber('')); // ""
console.log(formatNumber(null)); // ""
关键点
-
正则表达式解析:
/\B(?=(\d{3})+(?!\d))/g是\B:非单词边界,确保不在字符串开头匹配(?=...):正向预查,匹配位置而不消耗字符(\d{3})+:匹配一个或多个三位数字组(?!\d):负向预查,确保后面不再有数字
-
整数与小数分离:使用
split('.')分离,只对整数部分添加分隔符 -
负数处理:需要单独判断并处理负号,避免在负号后添加逗号
-
性能对比:
- 正则表达式:代码简洁,性能较好
- 循环遍历:逻辑清晰,易于理解
- toLocaleString:最简单,但灵活性较低
-
边界情况:注意处理空值、零、小于千的数字等特殊情况
-
扩展性:可以根据需求调整分隔符(如空格)或分隔位数(如万位分隔)
目录