数字分组使用正则表达式

3

有没有可能使用正则表达式进行数字分组(例如,将数字1000转换为字符串"1 000"),并且只需要一次扫描?(我知道某些系统中正则表达式和语言工具之间的界限有些模糊 - 回答前请听从您的良心。)

我提问的原因:最近另一个开发人员问我如何在JavaScript中执行数字分组,并向我展示了一个略有错误的JavaScript函数,其中使用了正则表达式。我给了他更好的替代方案,但他的正则表达式让我感到困扰,因为这种重写明显是正则文法应该能够完成的事情,但我确实不知道该如何编写正则表示式。

这是我的第一个天真的尝试,我知道它是不正确的:

function group(n) { return n.toString().replace(/(\d{3})/g, "$1 "); }

这种方法有两个缺点:group(1000)会生成"100 0",而group(100)会生成"100 "(末尾有空格)。您可以通过以下方式进行修复:
String.prototype.reverse = function () { 
    var a = []; 
    for (var i = this.length; i >= 0; --i) a.push(this[i]); 
    return a.join("");
}; 
function group(n) { 
    return n.toString().reverse().replace(/(\d{3})/g, "$1 ").
        trimRight().reverse(); 
}

但是这需要不止一个、两个、甚至三个,而是四个步骤(两个反转,一个替换和trimRight)!然后我冒险进入了回顾领域,并想出了以下解决方案:
function group(n) { return n.toString().replace(/(\d{3}(?!\d))/g, " $1");

...这根本不起作用(编辑-可能是因为我混淆了后顾和负面的前瞻...)- 它只匹配最后三位数(group(1000000000) 变成 "1000000 000")。前瞻效果稍微好一些:

function group(n) { return n.toString().replace(/(\d{3})(?=\d)/g, "$1 "); }

这更或多或少地让我回到了起点 - 我已经摆脱了尾随的空格,但是group(1000)仍然产生"100 0"
那么,能否通过单个正则表达式替换来完成此操作?我不关心使用哪种编程语言,因为这只需要使用正则表达式功能即可。
注意:这不是关于如何进行本地化的问题,我也不会进行过早的优化。我只是好奇是否可能,如果不可能,为什么不可能。

3
FYI,“(?!\d)”不是一个向后查找,而是一个负向前瞻。 - Alan Moore
@Alan Moore - 哦!这就解释了为什么它不起作用。 :) - gustafc
我知道这不是关于如何进行本地化的问题,但如果有人来到这里寻找答案,请使用Number.toLocaleString - ZachB
3个回答

8
这是一个适用于JavaScript的版本:
return n.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1 ");

5
这是用Perl实现的方式:
$num =~ s/(?<=\d)(\d{3})(?=(\d{3})*(\D|$))/ $1/g;

要分解它:
  • (?<=\d) - 我们使用回顾后发查找匹配项是否以数字开头

  • (\d{3}) - 我们正在寻找三个数字的组合

  • (?= - 我们使用前瞻,所以这三个数字必须跟随某些内容

  • (\d{3})* - 这将匹配0或多个由三个数字组成的组,即0、3、6... 个数字。

  • (\D|$) - 这将匹配一个非数字字符或字符串的结尾。

因此,我们要查找一个数字,后跟3个数字,后跟0、3、6...个数字,然后没有更多数字。

不幸的是,JavaScript 在其正则表达式中没有回顾后发,因此此模式在 JavaScript 中无法工作。如果您省略回顾后发,则会在具有 3、6、9... 个数字的数字前面添加一个前导空格。


4
n.toString().replace(/(\d)(?=(\d{3})+\b)/g,"$1 ")

在每个后面跟着3个i数字的数字后添加一个空格。例如,在 123456789 中,这些数字将被匹配:26
工作演示:http://jsbin.com/iruzu

+1 给这个演示,但您在替换字符串中遗漏了 $1。它正在显示 0001008 65 321,而不是 1 00010087 654 321 - Alan Moore
一个快速的推特确认:这是jsbin中的一个错误。https://twitter.com/rem/status/6727791738 - Kobi
这是一个很棒的资源,谢谢你让我知道它。 - Alan Moore

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接