使用regexp进行编号分组

gus*_*afc 3 regex language-agnostic

是否有可能做数分组(例如,将数字转换1000为字符串"1 000")使用一个通仅正则表达式?(我知道正则表达式和语言设施之间的界限在某些系统中有点模糊 - 在回复之前倾听你的良心.)

我之所以问的原因:另一个开发人员最近问我如何在JavaScript中进行数字分组,并使用regexp向我展示了一个稍微不正确的JavaScript函数.我给了他一个更好的选择,但他的正则表达式唠叨我,因为这种重写肯定是常规语法应该能做的事情,但我真的无法弄清楚如何为它编写正则表达式.

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

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

这种方法有两个缺陷; 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(); 
}
Run Code Online (Sandbox Code Playgroud)

但这不是一个,不是两个,不是三个,而是四个通道(两个反转,一个替换,和trimRight)!然后我冒险进入后面的土地,并提出:

function group(n) { return n.toString().replace(/(\d{3}(?!\d))/g, " $1");
Run Code Online (Sandbox Code Playgroud)

...根本不起作用(编辑 - 可能是因为我混淆了后视和负面前瞻......) - 它只匹配最后三位数(group(1000000000)变成"1000000 000").前瞻工作更好一点:

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

这或多或少让我回到了我开始的地方 - 我摆脱了尾随空间,但group(1000)仍然屈服"100 0".

那么 - 这可以通过单个regexp替换传递来完成吗?我是语言不可知的,因为这应该只需要使用正则表达式设施.

注意:这不是关于如何进行本地化的问题,我也没有参与过早的优化.我只是好奇这是否可能,如果不是,为什么不呢.

Ala*_*ore 8

这是一个适用于JavaScript的版本:

return n.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1 ");
Run Code Online (Sandbox Code Playgroud)


Dav*_*ebb 5

这是在Perl中完成的:

$num =~ s/(?<=\d)(\d{3})(?=(\d{3})*(\D|$))/ $1/g;
Run Code Online (Sandbox Code Playgroud)

分解:

  • (?<=\d) -我们正在使用后面的数字检查我们的比赛前面是否有数字

  • (\d{3}) -我们正在寻找一组三位数

  • (?= -我们正在使用前瞻功能,因此三个数字后面必须加上

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

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

因此,我们要查找一个数字,然后是3个数字,然后是0、3、6 ...个数字,然后没有其他数字。

不幸的是,JavaScript的正则表达式没有落后之处,因此该模式在JavaScript中不起作用。如果将外观放到后面,则会在3,6,9 ...位数字前加一个前导空格。