Angular TypeScript数字千分位格式化:规避Sonar正则性能警告及疑问
数字格式化解决方案(规避正则回溯风险)
一、Sonar警告的合理性
这个警告是合理的。如果你的原始正则包含嵌套量词、可选分支或无限制重复匹配,处理超长数字字符串时会触发大量回溯,导致CPU占用急剧升高,确实存在潜在的拒绝服务(DoS)风险——比如输入上百位的数字,低效正则可能会花费数秒甚至更久处理。
二、不使用正则的实现方案
手动处理整数部分的分组和开头零的去除,完全规避正则风险,逻辑清晰可控:
function formatNumber(num: number | string): string { // 统一转为字符串并去除首尾空白 const numStr = typeof num === 'number' ? num.toString() : num.trim(); // 拆分整数与小数部分 let [integerPart, decimalPart = ''] = numStr.split('.'); // 移除开头多余的零(全零则保留一个) let cleanedInteger = ''; let leadingZeroPassed = false; for (const char of integerPart) { if (char === '0' && !leadingZeroPassed) { continue; } leadingZeroPassed = true; cleanedInteger += char; } cleanedInteger = cleanedInteger || '0'; // 从后往前每三位添加空格分隔 let formattedInteger = ''; for (let i = cleanedInteger.length - 1, count = 0; i >= 0; i--) { formattedInteger = cleanedInteger[i] + formattedInteger; count++; if (count % 3 === 0 && i !== 0) { formattedInteger = ' ' + formattedInteger; } } // 补全小数部分到三位,不足补零 const formattedDecimal = decimalPart.padEnd(3, '0').slice(0, 3); return `${formattedInteger},${formattedDecimal}`; }
测试用例:
formatNumber(1234)→"1 234,000"formatNumber('000123456')→"123 456,000"formatNumber(789.12)→"789,120"formatNumber(0)→"0,000"
三、修复正则以消除Sonar警告
如果一定要保留正则实现,需优化表达式避免回溯风险,核心是使用高效的正向预查逻辑,确保匹配过程线性执行:
function formatNumberWithOptimizedRegex(num: number | string): string { const numStr = typeof num === 'number' ? num.toString() : num.trim(); let [integerPart, decimalPart = ''] = numStr.split('.'); // 移除开头多余的零:仅匹配开头连续的零(后面跟有效数字),替换为空 integerPart = integerPart.replace(/^0+(?=\d)/, '') || '0'; // 三位分组:用\B确保不在开头加空格,正向预查匹配末尾前的三位分组 const formattedInteger = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, ' '); // 补全小数部分 const formattedDecimal = decimalPart.padEnd(3, '0').slice(0, 3); return `${formattedInteger},${formattedDecimal}`; }
这个优化后的正则\B(?=(\d{3})+(?!\d))不会触发回溯,Sonar的静态分析会识别这种低风险写法,不再抛出警告。
内容的提问来源于stack exchange,提问作者Damian
相关产品推荐
相关产品推荐

