增强千位分隔符的正则表达式?

3

我看到了一个优美的脚本,可以给js数字添加千位分隔符:

function thousandSeparator(n, sep)
{
    var sRegExp = new RegExp('(-?[0-9]+)([0-9]{3})'),
        sValue = n + '';
    if(sep === undefined)
    {
        sep = ',';
    }
    while(sRegExp.test(sValue))
    {
        sValue = sValue.replace(sRegExp, '$1' + sep + '$2');
    }
    return sValue;
}

用法:

thousandSeparator(5000000.125, '\,') //"5,000,000.125"

然而,我对while循环有些困惑。

我考虑将正则表达式更改为:'(-?[0-9]+)([0-9]{3})*'星号...

但是,现在我该如何应用替换语句呢?

现在,我会有$1$2..$n

我该如何增强替换函数呢?

p.s. 代码取自这里 http://www.grumelo.com/2009/04/06/thousand-separator-in-javascript/


1
顺便说一下,它在 5000000.125678 上失败了 -> 5,000,000.125,678 - zerkms
@zerkms 是的,你是正确的。http://www.grumelo.com/2009/04/06/thousand-separator-in-javascript/ - Royi Namir
看看这个问题 - 里面有一个链接,指向一个示例,展示了如何实现你想要的功能。 - Rob I
@RobI 再次提醒,它仍然有一个 while 循环。我认为可以找到更好的解决方案...(或者不行)... :) - Royi Namir
@Cylian,我认为我们需要使用正向先行断言(-?[0-9]+)([0-9]{3})(?=\.),但它没有起作用...我的意思是,只替换右侧有小数点的数字。 - Royi Namir
@zerkms,我该如何让它只在左侧起作用? - Royi Namir
5个回答

8

谢谢。非常好。如果我在标签中写了[regex],我会选择这个答案。 - Royi Namir
那个人在他的回答中付出了很多努力,所以他无论如何都应该得到采纳;但是你真的不应该使用正则表达式来做这件事,本地方法更好(而且更容易理解)。 - andyrandy
1
你可以放心,我从现在开始会使用它 :) - Royi Namir
@luschen 我感觉自己像个新手,因为不知道这个。我觉得我写了很多次正则表达式来做这件事,但是根据我在这篇文章上的表现,每次都明显搞砸了,必须再次谷歌一下。不过这次我可能不会忘记它...再加上本地化,耶! - cfkane

5

你的假设

现在我将拥有$1和$2..$n

是错误的。你有两个组,因为你有两组括号。

    (-?[0-9]+)([0-9]{3})*
1.  ^^^^^^^^^^
2.            ^^^^^^^^^^

然后你需要重复第二组。如果第二次匹配成功,它会覆盖第一次匹配的结果,当第三次匹配时,它会覆盖...

这意味着在匹配完成后,$2 包含该组的最后一个匹配的值。

第一种方法

(\d)(?=(?:[0-9]{3})+\b)

并替换为

$1,

请参考这个链接

它的缺陷在于它会在小数点后面也插入逗号。(我正在修复这个问题。)

第二种方法

(\d)(?:(?=\d+(?=[^\d.]))(?=(?:[0-9]{3})+\b)|(?=\d+(?=\.))(?=(?:[0-9]{3})+(?=\.)))

替换为

$1,

请在Regexr上查看相关内容

现在变得有点复杂了。

(\d)                   # Match a digit (will be reinserted)
(?:
    (?=\d+(?=[^\d.]))  # Use this alternative if there is no fractional part in the digit
    (?=(?:\d{3})+      # Check that there are always multiples of 3 digits ahead
    \b)                # Till a word boundary
    |                  # OR
    (?=\d+(?=\.))      # There is a fractional part
    (?=(?:\d{3})+      # Check that there are always multiples of 3 digits ahead
    (?=\.))            # Till a dot
)

问题: 如果小数点后面没有字符串结束,则也匹配小数部分。

嗨stema,是的,你说得对。但是正如你所看到的,我面临着两个问题。它考虑来自右侧的数字123.1234567,而我需要摆脱while循环。 - Royi Namir
@RoyiNamir 我扩展了我的答案,但目前只针对第二个问题。第一个仍然是个问题。 - stema
@stema 看起来很不错,如果你能修复右侧的那个部分,我刚刚跟自己打了一赌输了。 - Dagg Nabbit
@ggg 你将拥有自己的5美元。 - Royi Namir
@RoyiNamir 我想我找到了一个解决方案,请测试一下。 - stema
@RoyiNamir,仅当小数部分后面是字符串的结尾时才有效。目前我不知道解决方案,JavaScript正则表达式太有限了。如果您只提供数字并以字符串结束,那么这应该可以工作。 - stema

1
这个怎么样?
result = "1235423.125".replace(/\B(?=(\d{3})+(?!\d))/g, ',') //1,235,423.125

2
试一下:"1235423.12342345".replace(/\B(?=(\d{3})+(?!\d))/g, ',') // "1,235,423.12,342,345" - Royi Namir

1

这是一个丑陋的脚本,与您美丽的脚本形成对比。

10000000.0001 .toString().split('').reverse().join('')
.replace(/(\d{3}(?!.*\.|$))/g, '$1,').split('').reverse().join('')

由于我们没有后顾之忧,所以我们可以通过反转字符串并使用前瞻来作弊。

这里再次以更易接受的形式呈现。

function thousandSeparator(n, sep) {

    function reverse(text) {
        return text.split('').reverse().join('');
    }

    var rx = /(\d{3}(?!.*\.|$))/g;

    if (!sep) {
        sep = ',';
    }

    return reverse(reverse(n.toString()).replace(rx, '$1' + sep));

}

我需要下载WinRAR才能使用这段代码吗?哈哈(非常长)...:) 谢谢 - Royi Namir
@RoyiNamir,你认为经过清理的版本怎么样?反转字符串对你来说不够好吗? - Dagg Nabbit
我已经在jsperf中测试过了,它非常慢(与主要示例相比-该示例在正确位置不使用逗号..)。我需要修复我的解决方案,使其首先从右侧获取仅数字,其次删除while循环。 - Royi Namir
1
@RoyiNamir 嗯,这确实解决了这两个问题,但我不怀疑像这样反转字符串会很慢...我认为环视也可能很慢。好奇看看其他人会想出什么。 - Dagg Nabbit
我认为我们需要先完成第一阶段...如何使其仅在左侧数字上工作... - Royi Namir

0

试试这个:

result = subject.replace(/([0-9]+?)([0-9]{3})(?=.*?\.|$)/mg, "$1,$2");

测试 这里


不错,但它也在小数点右边的部分放置逗号 :( - Dagg Nabbit
123456.134'.replace(/([0-9]+?)([0-9]{3})(?=.*?\.|$)/mg, "$1,$2") 的结果是 "1,23456.134" - Royi Namir

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