【正则表达式】使用逗号将数字三位三位地分开

背景介绍

在一个项目中,需要显示一个 YouTube 视频被观看了多少次,这个数字一般是个很长的数字,为了更好的体验,也是国际标准,三位三位地断开,对应千(thousand),百万(million),十亿(billion),当然对中国用户来讲,不是特别友好,中国人喜欢四位四位隔开,对应万,亿,万亿。。。但是无论如何,都比看到 567232349723 这样的一串数字好很多。
言归正传,这个该如何实现呢?以下就以 567232349723 数字为例。

普通的解决办法

首先,可以这样理解,就是从数字的最后一位开始,往前数,数到 3,加一个逗号,如此循环下去……直到第一个数字(因为逗号不能加在开始位置,比如不能“,123”)。

1
2
3
4
5
6
7
var array = '567232349723'.split('');
for (var i = array.length - 1, j = 1; i > 0; i--, j++) {
if (j % 3 === 0) {
array.splice(i, 0, ',');
}
}
console.log(array.join(''));

受不了了,看似特别简单的问题,要写那么长一段代码。从标题你就看到了,这不是我们想要的答案,我们将要使用正则表达式来解决这个问题。首先来明确几个概念:

零宽断言(零宽度正预测先行断言):形式为(?=exp)零宽,就是不匹配任何内容,明确一点就是它表示的是一个位置,就像^, \$一样。断言,就是说它需要满足一定条件。

负向零宽断言(零宽度负预测先行断言):形式为(?!exp)。所谓负向,就是不满足某种条件。

这两个别名都含有“先行”二字,它表示匹配的位置是表达式前面的位置。这么说来,肯定还会有一种用于匹配表达式后面的位置。你说的对,还有“零宽度正回顾后发断言”,形式为(?<=exp),以及“零宽度负回顾后发断言”,形式为(?<!exp)。但是在 javascript 中并不支持这两中形式。这次不多说明。

###正则表达式办法
我们现在看看哪些位置需要添加逗号,首先这个位置不能是开始位置,也就是(?!^),其次这个位置后面总是有 3n(n > 0)个数字,直到结束,也就是(\d{3})+$,组合起来就是(?=(?!^)(\d{3})+$)

所以答案就是

1
'567232349723'.replace(/(?=(?!^)(\d{3})+$)/g, ',');

注意了,以上正则对于整数已经足够了,加入你想也适应于小数呢?比如“123456.123456”,这时候我们只处理前面几位,所以上面的“直到结束”应该修改为“直到结束或者小数点”,那么答案来了,就是[$\.],所以适用于小数的正则为

1
'567232.49723'.replace(/(?=(?!^)(\d{3})+[$\.])/g, ',');

如果想适用更多情况,会使得你的正则越来越复杂,也越来越容易出错,所以要根据你实际需要来决定,不多不少最好。

工具推荐

  1. http://www.regexper.com/
  2. Windows 系统上的RegExpBuddy,收费约 40 美元。