在C#中重复字符的最佳方法是什么?

1022

在C#中生成一串\t的最佳方法是什么?

我正在学习C#,并尝试用不同的方式表达相同的意思。

Tabs(uint t)是一个返回带有t\tstring的函数。

例如,Tabs(3)返回"\t\t\t"

这三种实现Tabs(uint numTabs)的方式哪种最好呢?

当然,这取决于“最好”的含义。

  1. LINQ版本只有两行,很好。 但是,对Repeat和Aggregate的调用是否不必要地消耗时间/资源?

  2. StringBuilder版本非常清晰,但是StringBuilder类是否更慢?

  3. string版本很基本,这意味着它很容易理解。

  4. 这完全没有关系吗? 它们都是平等的吗?

这些都是帮助我更好地了解C#的问题。

private string Tabs(uint numTabs)
{
    IEnumerable<string> tabs = Enumerable.Repeat("\t", (int) numTabs);
    return (numTabs > 0) ? tabs.Aggregate((sum, next) => sum + next) : "";
}

private string Tabs(uint numTabs)
{
    StringBuilder sb = new StringBuilder();
    for (uint i = 0; i < numTabs; i++)
        sb.Append("\t");

    return sb.ToString();
}

private string Tabs(uint numTabs)
{
    string output = "";
    for (uint i = 0; i < numTabs; i++)
    {
        output += '\t';
    }
    return output;
}
21个回答

1875
这个内容如何:

这是什么:

string tabs = new string('\t', n);

其中n是您想要重复字符串的次数。

或者更好地说:

static string Tabs(int n)
{
    return new string('\t', n);
}

2
有没有办法重复这个过程来处理一个单词?而不是使用 '\t',如何使用 "time"? - asdfkjasdfjk
6
@user1478137 或者更好的是(也在下面):这里 - Xynariz
当将 '\t' 替换为一个空格(即 " ")时,我发现在某些笔记本电脑上它被视为一个空格,在其他一些笔记本电脑上,在行末的空格后面会添加一个“回车键”。下面提供的另一个答案,使用 string.Concat,也在某些笔记本电脑上表现出同样奇怪的方式。有什么想法是为什么会发生这种情况吗?谢谢。 - progLearner

226

3
请使用StringBuilder来实现,避免使用Linq,并优化性能! - Bitterblue
5
“StringBuilder”不一定更快。https://dev59.com/JXRB5IYBdhLWcg3wkH9N - Schiavini
6
如果您事先指定正确的容量,它可能不会更快,但可以节省内存分配(压力),这与分析的微基准一样重要。 - wekempf
5
变量 strRepeat 的值是将字符串 "ABC" 重复一百万次所组成的字符串,使用 Enumerable.Repeat 方法实现,并通过 string.Concat 方法拼接起来。这段代码的运行时间为 50 毫秒。 - yongfa365
那怎么回答问题呢?问题是“在C#中生成一串\t的最佳方法是什么?”一个问题不仅仅是标题。还有关于三种具体的实现方法。 - Peter Mortensen

151
在所有版本的.NET中,您可以这样重复一个字符串:
public static string Repeat(string value, int count)
{
    return new StringBuilder(value.Length * count).Insert(0, value, count).ToString();
}

要重复一个字符,new String('\t', count)是最好的选择。请参见@CMS的答案

9
就性能而言,这无疑是String最快的方法。其他方法会创建太多额外开销。 - midspace
@midspace 你知道有没有人解释为什么其他答案更差吗?我本来以为原生的String.Concat在内部优化上和StringBuilder一样。 - Marie
@Marie 以下文章解释了一些优点。 https://support.microsoft.com/en-au/help/306822/how-to-improve-string-concatenation-performance-in-visual-c 另外两个因素是,StringBuilder允许字符串,并且不仅限于一个字符(虽然这与原始问题无关),而上面的string.Concat答案必须首先使用Enumerable.Repeat创建一个数组。正如我所说,这是不必要的开销。 - midspace
我原以为它不会先创建一个数组,因为它可以逐个迭代项目。谢谢你提供的链接,我会阅读一下! - Marie

68
最好的方法当然是使用内置方式:
string Tabs(int len) { return new string('\t', len); }

在其他解决方案中,应优先选择最简单的;只有当这种方法证明过慢时,才应努力寻找更高效的解决方案。

如果您使用StringBuilder并预先知道其结果长度,则还应使用适当的构造函数,因为这样可以节省时间并避免不必要的数据复制。废话:当然上面的代码更有效率。


8
我的基准测试显示,使用new string('\t', len)要比使用StringBuilder方法快2倍到7倍不等。您认为为什么在这种情况下StringBuilder更有效? - StriplingWarrior
6
@StriplingWarrior 感谢您纠正这个错误(毕竟它一直存在了两年之久!)。 - Konrad Rudolph

54

扩展方法:

public static string Repeat(this string s, int n)
{
    return new String(Enumerable.Range(0, n).SelectMany(x => s).ToArray());
}

public static string Repeat(this char c, int n)
{
    return new String(c, n);
}

11
Enumerable.Range(0, n).SelectMany(x => s) 可以简单地替换为 Enumerable.Repeat(s, n) - Palec
5
不可以。对于每个虚拟的 xSelectMany 方法将生成一个 char 值序列(因为字符串 s 实现了 IEnumerable<char> 接口),然后将所有这些 char 序列连接成一个长的 char 序列。而你提出的方法将生成一个 IEnumerable<string>,这与前者不同。 - Jeppe Stig Nielsen
2
我错了,@JeppeStigNielsen。感谢你的提醒。如果我真的想使用Enumerable.Repeat,我必须将字符串连接在一起:string.Concat(Enumerable.Repeat(s, n))。这已经被发布过了 - Palec

43
使用扩展方法:
public static class StringExtensions
{
   public static string Repeat(this char chatToRepeat, int repeat) {

       return new string(chatToRepeat, repeat);
   }

   public  static string Repeat(this string stringToRepeat, int repeat)
   {
       var builder = new StringBuilder(repeat*stringToRepeat.Length);
       for (int i = 0; i < repeat; i++) {
           builder.Append(stringToRepeat);
       }
       return builder.ToString();
   }
}

你可以这样写:

Debug.WriteLine('-'.Repeat(100)); // For Chars
Debug.WriteLine("Hello".Repeat(100)); // For Strings

请注意,使用StringBuilder版本而不是字符串来进行简单字符的性能测试会给您带来重大的性能惩罚:
在我的电脑上,测量性能的差异为1:20,其中一个使用了StringBuilder版本,另一个使用了字符串。
Debug.WriteLine('-'.Repeat(1000000)) // Char version

并且

Debug.WriteLine("-".Repeat(1000000)) // String version

2
字符串版本的性能可以通过使用StringBuilder.Insert(Int32, String, Int32)进行改进,正如Binoj Anthony所回答的那样 - Palec
我使用了这段代码,对我来说很好。但是这个问题的其他答案也很好。 - Hesan Mahdi

26

假设您想重复'\t' n次,可以使用以下方法:

String.Empty.PadRight(n,'\t')

1
谢谢。这也非常快。http://codereview.stackexchange.com/questions/36391/adding-n-characters-to-a-string - SunsetQuest
我一直都是这样做的。即使包装在扩展方法中,它也比这里发布的其他实现更简单。请注意,OP只想重复\t,而不是字符串。 - Michael Ribbons

25
这个怎么样?
//Repeats a character specified number of times
public static string Repeat(char character,int numberOfIterations)
{
    return "".PadLeft(numberOfIterations, character);
}

//Call the Repeat method
Console.WriteLine(Repeat('\t',40));

6
哈哈...这是我曾经陷入这种情况时能想到的。但个人认为 new string('\t', 10) 是最好的解决方案。 - shashwat

25

有一种简单的方法可以重复一个字符串,即使在.NET 2.0中也适用。

要重复一个字符串:

string repeated = new String('+', 3).Replace("+", "Hello, ");

返回

"你好,你好,你好,"

将字符串重复为数组:

// Two line version.
string repeated = new String('+', 3).Replace("+", "Hello,");
string[] repeatedArray = repeated.Split(',');

// One line version.
string[] repeatedArray = new String('+', 3).Replace("+", "Hello,").Split(',');

返回

{"你好", "你好", "你好", ""}

保持简单。


那怎么回答问题呢?问题是“在C#中生成一串\t的最佳方法是什么?”一个问题不仅仅是标题。还有关于三种具体的实现方法。 - Peter Mortensen

19

您的第一个示例使用Enumerable.Repeat

private string Tabs(uint numTabs)
{
    IEnumerable<string> tabs = Enumerable.Repeat(
                                 "\t", (int) numTabs);
    return (numTabs > 0) ? 
            tabs.Aggregate((sum, next) => sum + next) : ""; 
} 

可以使用 String.Concat 更紧凑地重写:

private string Tabs(uint numTabs)
{       
    return String.Concat(Enumerable.Repeat("\t", (int) numTabs));
}

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