自动将数字转换为逗号版本

时间:2009-07-25 14:59:15

标签: .net regex text formatting

给出以下文字

/feeds/tag/remote-desktop                               1320  17007    22449240
/feeds/tag/terminal-server                              1328  15805    20989040
/foo/23211/test                                         1490  11341    16898090

假设我们想将这些数字转换为其逗号形式,如此

/feeds/tag/remote-desktop                             1,320  17,007  22,449,240
/feeds/tag/terminal-server                            1,328  15,805  20,989,040
/foo/23211/test                                       1,490  11,341  16,898,090

(不要担心修复固定宽度的ASCII间距,这是另一天的问题)

这是我能想到的最好的正则表达式;它基于Regex Ninja Steven Levithan的this JavaScript regex solution

return Regex.Replace(s, @"\b(?<!\/)\d{4,}\b(?<!\/)", 
    delegate(Match match) {
        string output = "";
        string m = match.Value;
        int len = match.Length;
        for (int i = len - 1; i >= 0 ; i--)
        {                        
            output = m[i] + output;
            if ((len - i) % 3 == 0) output = "," + output;
        }
        if (output.StartsWith(","))
            output = output.Substring(1, output.Length-1);
        return output;
    });

related question中,有一个非常聪明的数字逗号插入正则表达式建议:

text = Regex.Replace(text, @"(?<=\d)(?=(\d{3})+$)", ",")

然而,这需要结束锚$ ,正如您所看到的,我在上面的文字中没有 - 数字在其余部分中“浮动”文本。

我怀疑有一种比我的解决方案更简洁的方法吗?写完这篇文章之后,我才意识到我可以将它们组合起来,并将一个正则表达式放在另一个中,如下所示:

return Regex.Replace(s, @"\b(?<!\/)\d{4,}\b(?<!\/)", 
    delegate(Match match) {
        return Regex.Replace(match.Value, @"(?<=\d)(?=(\d{3})+$)", ",");
    });

6 个答案:

答案 0 :(得分:17)

为什么你不能将它们解析为long然后使用格式化的ToString?

CultureInfo ci = new CultureInfo("en-US");
long number = 1234;
Console.WriteLine(number.ToString("N0", ci));

答案 1 :(得分:7)

我原则上同意那些建议您尽可能使用内置.NET格式设施的建议。

但是,如果您的数字可以任意大,那么这样的事情应该有效:

int len = match.Length;
int numCommas = (len-1) / 3;
StringBuilder sb = new StringBuilder(match.Value, len + numCommas)
for (int i = 1; i <= numCommas; i++) {
    sb.Insert(len - i * 3, ',');
}
return sb.ToString()

此外,如果您因任何原因坚持使用Regex.Replace,您可以调整问题中列出的正则表达式以避免结束锚点问题。例如,我认为

Regex.Replace(text, @"(?<=\d)(?=(\d{3})+(\s|$))", ",")

可以在你的例子中使用,因为你想要“逗号”的数字后面跟着空格或行尾。

答案 2 :(得分:6)

为什么不(在你的代表内):

CultureInfo ci = new CultureInfo("en-US");
string output = int.Parse(match.Value).ToString("N0",ci);

翻译:

  1. 转换为int(或者如果需要,则为long)
  2. 使用.net数字格式正确插入逗号

答案 3 :(得分:3)

为什么不将它们分成单独的,修剪过的字段,然后使用“聪明”插入Regex处理每个数字字段?这实际上可以帮助您使用固定宽度格式,因为您可以在重构线时使用string.Format指定宽度。

实际上,如果将它们拆分为转换为数字并使用格式说明符添加逗号,则可能更容易。

答案 4 :(得分:2)

在他的“掌握正则表达式”一书中,Jeffrey EF Friedl对这个“经典”的commafication问题给出了一个很好的解释(解释了外观概念),在第65页上他提供了以下可能对你有帮助的Perl代码片段:

$string =~ s/(?<=\d)(?=(\d\d\d)+$)/,/g;

答案 5 :(得分:2)

为什么这么复杂?

var text =
@"/feeds/tag/remote-desktop             1320  17007    22449240
/feeds/tag/terminal-server            1328  15805    20989040
/foo/23211/test                       1490  11341    16898090";

var regex = new Regex(@"(?<=\s)\d+");

for (var match = regex.Match(text) ; match.Success ; match = match.NextMatch())
{
    var longValue = long.Parse(match.Value);
    text = text.Replace(match.Value, longValue.ToString("n0"));
}

Console.WriteLine(text);

产生:

/feeds/tag/remote-desktop             1,320  17,007    22,449,240
/feeds/tag/terminal-server            1,328  15,805    20,989,040
/foo/23211/test                       1,490  11,341    16,898,090

这样做的好处是对那些每四个字符使用下划线的文化使用文化敏感的格式,而不是每三个字符使用逗号。 ;)

如果你担心long可能不够大(!)那么也许.NET 4的System.Numerics.BigInteger应该可以胜任。