【问题标题】:Formatting alphanumeric string格式化字母数字字符串
【发布时间】:2010-02-18 07:55:53
【问题描述】:

我有一个包含 16 个字母数字字符的字符串,例如F4194E7CC775F003。我想将其格式化为 F419-4E7C-C775-F003。

我尝试过使用

string.Format("{0:####-####-####-####}","F4194E7CC775F003");

但这不起作用,因为它不是数值。

所以我想出了以下内容:

public class DashFormatter : IFormatProvider, ICustomFormatter
{
  public object GetFormat(Type formatType)
  {
    return this;
  }

  public string Format(string format, object arg, IFormatProvider formatProvider)
  {
    char[] chars = arg.ToString().ToCharArray();
    StringBuilder sb = new StringBuilder();

    for (int i = 0; i < chars.Length; i++)
    {
      if (i > 0 && i % 4 == 0)
      {
        sb.Append('-');
      }

      sb.Append(chars[i]);
    }

    return sb.ToString();
  }
}

并通过使用

string.Format(new DashFormatter(), "{0}", "F4194E7CC775F003");

我能够解决问题,但是我希望有更好/更简单的方法来解决这个问题?也许是一些 LINQ 魔法?

谢谢。

【问题讨论】:

  • 我认为这很简单,但遗憾的是,它不起作用:string.Format("{0}{1}{2}{3}-{4}{5}{6}{7}-{8}{9}{10}{11}-{12}{13}{14}{15}", aString.ToCharArray());
  • string.format 需要参数列表。 aString.ToCharArray() 被视为一个数组参数。

标签: c# string formatting


【解决方案1】:

不用Linq也可以一行完成:

        StringBuilder  splitMe = new StringBuilder("F4194E7CC775F003");
        string joined = splitMe.Insert(12, "-").Insert(8, "-").Insert(4, "-").ToString();

【讨论】:

  • +1 比我的好,而且比任何 LINQ 解决方案都好
  • 我想知道哪个效率更高,你的还是我的,所以我做了一个快速的基准测试 - 你的速度是原来的两倍 ;-)
  • 很好,但我认为那是两行。
  • 它可以在一行中重写为字符串加入 = new StringBuilder("F4194E7CC775F003").Insert(12, "-").Insert(8, "-").Insert(4, " -").ToString();
  • @Adam:性能与 OP 的解决方案相比如何?
【解决方案2】:

你可以用正则表达式来做,虽然我不知道与其他方法相比它的性能如何。

string formattedString = Regex.Replace(yourString, "(\\S{4})\\B", "$1-");

如果你愿意,你也可以把它放在字符串的扩展方法中:

yourString.ToDashedFormat();

【讨论】:

  • 抱歉,这比 Carra 的解决方案慢 25 倍
  • 哎哟!好吧,我确实说过我不知道表演会是什么样子!
【解决方案3】:

如果你想要它 linq:

var formatted = string.Join("-", Enumerable.Range(0,4).Select(i=>s.Substring(i*4,4)).ToArray());

如果你希望它高效:

var sb = new StringBuilder(19);
sb.Append(s,0,4);
for(var i = 1; i < 4; i++ )
{
 sb.Append('-');
 sb.Append(s,i*4, 4);
}
return sb.ToString();

我没有对这个进行基准测试,但我认为它会比 StringBuilder.Insert 更快,因为它不会多次移动字符串的其余部分,它只会写入 4 个字符。 它也不会重新分配底层字符串,因为它在一开始就被预分配了 19 个字符。

【讨论】:

  • 但我认为你缺少强制转换 var s= string.Join("-", Enumerable.Range(0, 4).Select(i => "F4194E7CC775F003".Substring(i * 4, 4 )).ToArray());
  • 它可能看起来很酷,但效率很低。我刚刚做了一些基准测试,Carra 的解决方案快了 3 倍
  • 是的,抱歉,我没有尝试编译,现在已更正。我实际上使用的是我自己的字符串扩展,它看起来像 foo.Select(bar).JoinWithSeparator('-')
  • 是的,我同意它效率低下。最有效的方法是使用 C++ 风格的字符数组,而不是字符串生成器。
  • @George - “使用 C++ 风格的字符数组” - 我相信这正是 StringBuilder 在内部所做的
【解决方案4】:

基于Carra's answer我做了这个小实用方法:

private static string ToDelimitedString(string input, int position, string delimiter)
{
  StringBuilder sb = new StringBuilder(input);

  int x = input.Length / position;

  while (--x > 0)
  {
    sb = sb.Insert(x * position, delimiter);
  }

  return sb.ToString();
}

你可以这样使用它:

string result = ToDelimitedString("F4194E7CC775F003", 4, "-");

还有一个测试用例:

[Test]
public void ReturnsDelimitedString()
{
  string input = "F4194E7CC775F003";

  string actual = ToDelimitedString(input, 4, "-");

  Assert.AreEqual("F419-4E7C-C775-F003", actual);
}

【讨论】:

    【解决方案5】:
     char[] chars = "F4194E7CC775F003".ToCharArray();
                var str = string.Format("{0}-{1}-{2}-{3}"
                                      , new string(chars.Take(4).ToArray())
                                      , new string(chars.Skip(4).Take(4).ToArray())
                                      , new string(chars.Skip(8).Take(4).ToArray())
                                      , new string(chars.Skip(12).Take(4).ToArray())  
                    );
    

    【讨论】:

    【解决方案6】:

    我能想到的最简单的解决方案是

            var text = "F4194E7CC775F003";
            var formattedText = string.Format(
                "{0}-{1}-{2}-{3}",
                text.Substring(0, 4),
                text.Substring(4, 4),
                text.Substring(8, 4),
                text.Substring(12, 4));
    

    【讨论】:

    • Carra 的解决方案速度是原来的两倍
    【解决方案7】:

    仅 9 年后,与 Carra 的回答略有不同。根据我的测试,这产生了大约 2.5 倍的速度提升(将所有“-”更改为“-”):

            StringBuilder initial = new StringBuilder("F4194E7CC775F003");
            return initial.Insert(12, '-').Insert(8, '-').Insert(4, '-').ToString();
    

    【讨论】:

      猜你喜欢
      • 2012-04-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-16
      • 1970-01-01
      相关资源
      最近更新 更多