代码之家  ›  专栏  ›  技术社区  ›  Jeff Atwood

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

  •  -3
  • Jeff Atwood  · 技术社区  · 17 年前

    鉴于以下案文

    /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间距,这是另一天的问题)

    this JavaScript regex solution 来自Regex Ninja Steven Levithan:

    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 回复  |  直到 9 年前
        1
  •  17
  •   maciejkow    17 年前

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

    CultureInfo ci = new CultureInfo("en-US");
    long number = 1234;
    Console.WriteLine(number.ToString("N0", ci));
    
        2
  •  7
  •   kvb    17 年前

    但是,如果您的数字可以任意大,那么类似的方法应该可以工作:

    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|$))", ",")
    

    在您的示例中可能会起作用,因为要“逗号fy”的数字后面都跟有空格或行尾。

        3
  •  6
  •   Keltex    17 年前

    为什么不(在您的代理中):

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

    翻译:

    1. 转换为int(或long,如果需要)
        4
  •  3
  •   tvanfosson    17 年前

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

        5
  •  2
  •   Thijs    17 年前

    Jeffrey E.F.Friedl在其著作《掌握正则表达式》中对这一“经典”通信问题给出了很好的解释(以解释环视概念),在第65页,他给出了以下Perl代码片段,可能对您有所帮助:

    $string =~ s/(?<=\d)(?=(\d\d\d)+$)/,/g;
    
        6
  •  2
  •   Damian Powell    16 年前

    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 可能不够大(!)那么可能是.NET4 System.Numerics.BigInteger 我应该做这项工作。