有没有一种简单的方法可以将字符串重复X次?


318

我正在尝试根据项目深度在字符串之前插入一定数量的缩进,并且我想知道是否有办法返回重复X次的字符串。例:

string indent = "---";
Console.WriteLine(indent.Repeat(0)); //would print nothing.
Console.WriteLine(indent.Repeat(1)); //would print "---".
Console.WriteLine(indent.Repeat(2)); //would print "------".
Console.WriteLine(indent.Repeat(3)); //would print "---------".

9
不知道这是否适用,但是您可能也想看看IndentedTextWriter
克里斯·舒特

您是否要考虑更改接受的答案,因为您的问题是关于重复字符串而不是接受的答案所描绘的字符?直到今天,直到.Net v4.7为止,任何重载的Stringclass 构造函数都不会将字符串作为参数来从中创建重复项,这可能会使已接受的答案非常合适。
RBT

Answers:


537

如果只打算重复相同的字符,则可以使用接受char和重复次数的字符串构造函数new String(char c, int count)

例如,要重复五次破折号:

string result = new String('-', 5);
Output: -----

7
感谢您提醒我有关此出色的小功能。我认为它迷失在我的脑海。
克里斯·舒特

3
由于制表符元字符'\ t'是一个字符,因此也适用于缩进。
cori 2012年

91
这是C#的一个非常有用的技巧,但问题的标题是询问字符串(不是char)。这个答案下面的其他答案实际上是在回答这个问题,但评级要低得多。我并不是想不尊重艾哈迈德的回答,但我认为应该改变这个问题的标题(如果问题实际上是关于字符的),或者应该真正地推翻其他答案(而不是这个问题)。
pghprogrammer13年

14
@Ahmad正如我说的那样,我之所以投票不是因为我认为您没有提供很好的信息,而是因为您提供的信息与回答当前所说的问题无关。想象一下,如果您正在寻找一种重复字符串(而不是字符)的方法,并且当您找到相关问题时,您必须滚动浏览几个“有用的”提示以获取问题的实际答案。如果反对票对您不利,我可以将其删除。但是你看到我来自哪里吗?我在这里完全是基地吗?
pghprogrammer13年

11
@ pghprogrammer4恕我直言,downvotes可能非常令人气disc,仅应用于有害/误导/ truly_bad的答案,需要进行重大更改或应由其作者删除。之所以存在答案,是因为人们慷慨大方并希望分享自己的知识。通常,这些站点实际上是在鼓励投票的前提下,将有用的答案带到顶部。
制造商史蒂夫(Steve)2014年

271

如果您使用的是.NET 4.0,则可以string.Concat与一起使用Enumerable.Repeat

int N = 5; // or whatever
Console.WriteLine(string.Concat(Enumerable.Repeat(indent, N)));

否则我会选择亚当的答案

我通常建议使用Andrey的答案的原因仅仅是,该ToArray()调用会引入多余的开销,StringBuilder而Adam提出的方法可以避免这种开销。就是说,至少它不需要.NET 4.0就可以工作。而且它既快捷又容易(如果效率不是您所关注的重点,那也不会杀死您)。


3
这可以很好地与字符串配合使用-就像您需要连接不间断空格( )一样。但是我认为如果您要处理字符,字符串构造函数将是最快的...
woodbase 2012年

1
字符串构造函数仅适用于一个字符。使用Concat Repeat的选项将适用于字符串
Eli Dagan

4
感谢您回答实际标题问题!
Mark K Cowan

我喜欢这个答案!
Ji_in_coding

如果您获得-System.Linq.Enumerable等作为输出,这是因为您(好吧,这是我)太快了,无法复制/粘贴和修改代码段。如果需要在Enumerable.Repeat的输出上连接不同的字符串,则需要这样做: Console.WriteLine(string.Concat("-", string.Concat(Enumerable.Repeat(indent, N))));
Gabe

47
public static class StringExtensions
{
    public static string Repeat(this string input, int count)
    {
        if (!string.IsNullOrEmpty(input))
        {
            StringBuilder builder = new StringBuilder(input.Length * count);

            for(int i = 0; i < count; i++) builder.Append(input);

            return builder.ToString();
        }

        return string.Empty;
    }
}

6
还可以传递input.Length * countStringBuilder构造函数,您不觉得吗?
丹涛

如果你通过 input.Length * countStringBuilder构造函数,则可以StringBuilder完全跳过并立即创建正确大小的char []。
dtb

@dtb:我很好奇你为什么要这么做。我无法想象这会比使用StringBuilder,并且代码的透明度会降低。
亚当·罗宾逊

@dtb:太好了。使用StringBuilder; 它旨在有效地做到这一点。
制造商史蒂夫(Steve)2014年

亚当,我看到您在将输入添加到count时遇到了测试输入为null的麻烦,但是后来让它落空了,依靠Append在给出null的情况下什么也不做。恕我直言,这不太明显:如果可能为null,为什么不先进行测试并返回空字符串?
制造商史蒂夫(Steve)2014年

46

最有效的弦乐解决方案

string result = new StringBuilder().Insert(0, "---", 5).ToString();

1
当然可以。当然不是最出色的。StringBuilder在很少的串联数量上有一些开销。
Teejay

25

在许多情况下,这可能是最简洁的解决方案:

public static class StringExtensions
{
    public static string Repeat(this string s, int n)
        => new StringBuilder(s.Length * n).Insert(0, s, n).ToString();
}

用法是:

text = "Hello World! ".Repeat(5);

这基于其他答案(尤其是@ c0rd的答案)。除了简单之外,它还具有以下功能,并非所讨论的所有其他技术都具有这些功能:

  • 重复任意长度的字符串,不仅是字符(应OP的要求)。
  • StringBuilder通过存储预分配有效地使用。

我同意,这太好了。我刚刚将这添加到我的代码中,感谢Bob!谢谢!
约翰·伯利

22

如果所需的字符串仅包含一个字符,请使用String.PadLeft

public static string Indent(int count, char pad)
{
    return String.Empty.PadLeft(count, pad);
}

此处付款


1
吻。无论如何,我们需要StringBuilders和扩展用于什么?这是一个非常简单的问题。
DOK 2010年

1
我不知道,这似乎以某种优雅的方式解决了这个问题。顺便说一句,你叫谁“ S”?:-)
史蒂夫·汤森

7
但这不是只是一个不太明显的采用a 和an string构造函数charint版本吗?
丹涛

用String.Empty代替“” ...看起来更好,否则,很好的解决方法;)
Thomas Levesque 2010年

@Steve顺便说一句,String.PadLeft参数是相反的。该count填充字符之前。
艾哈迈德·玛吉

17

您可以重复您的字符串(以防它不是单个字符)并合并结果,如下所示:

String.Concat(Enumerable.Repeat("---", 5))

12

我会去找Dan Tao的答案,但是如果您不使用.NET 4.0,则可以执行以下操作:

public static string Repeat(this string str, int count)
{
    return Enumerable.Repeat(str, count)
                     .Aggregate(
                        new StringBuilder(),
                        (sb, s) => sb.Append(s))
                     .ToString();
}

3
如果在我的项目中找到此代码段,我会怀疑谁一直在违反KISS以及为什么...很好……否则
Noctis 2014年

4
        string indent = "---";
        string n = string.Concat(Enumerable.Repeat(indent, 1).ToArray());
        string n = string.Concat(Enumerable.Repeat(indent, 2).ToArray());
        string n = string.Concat(Enumerable.Repeat(indent, 3).ToArray());

1
@Adam:我想您需要在.NET 4.0之前执行该操作。
丹涛

3

我喜欢给出的答案。沿着相同的路线,虽然是我过去使用的:

“” .PadLeft(3 * Indent,'-')

这将完成缩进,但从技术上讲,问题是重复字符串。如果字符串缩进是>-<之类的内容,则此以及已接受的答案均不起作用。在这种情况下,c0rd使用stringbuilder的解决方案看起来不错,尽管stringbuilder的开销实际上可能不会使其性能最高。一种选择是建立一个字符串数组,用缩进字符串填充它,然后进行连接。白衣:

int Indent = 2;

string[] sarray = new string[6];  //assuming max of 6 levels of indent, 0 based

for (int iter = 0; iter < 6; iter++)
{
    //using c0rd's stringbuilder concept, insert ABC as the indent characters to demonstrate any string can be used
    sarray[iter] = new StringBuilder().Insert(0, "ABC", iter).ToString();
}

Console.WriteLine(sarray[Indent] +"blah");  //now pretend to output some indented line

我们都喜欢一个聪明的解决方案,但有时候简单是最好的。


3

添加扩展方法我正在使用所有项目:

public static string Repeat(this string text, int count)
{
    if (!String.IsNullOrEmpty(text))
    {
        return String.Concat(Enumerable.Repeat(text, count));
    }
    return "";
}

希望有人可以使用它...


2

惊讶的是没人上过老派。我没有对这段代码提出任何要求,只是为了好玩:

public static string Repeat(this string @this, int count)
{
    var dest = new char[@this.Length * count];
    for (int i = 0; i < dest.Length; i += 1)
    {
        dest[i] = @this[i % @this.Length];
    }
    return new string(dest);
}

显然,我把它留给了精明的读者作为测试:)非常精明,谢谢。
OlduwanSteve

1
命名参数@this并没有什么老套,这一直是一个可怕的主意:)
Dave Jellison

2
我宁愿不要将关键字用作变量名,除非强制使用(例如@class =“ something”在使用MVC时,因为您需要引用CSS的类,但这是C#中的关键字(当然)。这不仅仅是我在说,这是一般的经验法则。尽管它肯定是可编译的代码,而且合法,但也考虑一下易于阅读和键入的原因,这两个实用原因。我非常偏爱使用参数名称来描述首先发生的事情,因此请重复(此字符串种子, int count)可能是更具说明性的恕我直言
Dave Jellison

1
有趣,谢谢。我认为在这种情况下,@ this的描述性可能不那么正确。但是总的来说,在“ this”的唯一合理名称相当通用的情况下,扩展类或接口是相当普遍的。如果您有一个名为'instance'或'it'或'str'的参数(请参阅MSDN),那么您可能的意思是'this'。
OlduwanSteve

1
我基本上同意您的观点,但是为了争辩……因为我对我正在构建的字符串了解更多,所以我可以做的比StringBuilder稍好一些。StringBuilder必须在分配内存时进行猜测。当然,在许多情况下这不太重要,但是在那里有人可能会并行构建大量重复的字符串,并且很高兴获得一些时钟周期:)
OlduwanSteve 2014年

2

不知道这将如何执行,但这是一段简单的代码。(我可能使它看起来比实际更复杂。)

int indentCount = 3;
string indent = "---";
string stringToBeIndented = "Blah";
// Need dummy char NOT in stringToBeIndented - vertical tab, anyone?
char dummy = '\v';
stringToBeIndented.PadLeft(stringToBeIndented.Length + indentCount, dummy).Replace(dummy.ToString(), indent);

另外,如果您知道可以期望的最大级别数,则可以声明一个数组并对其进行索引。您可能希望将此数组设为静态或常量。

string[] indents = new string[4] { "", indent, indent.Replace("-", "--"), indent.Replace("-", "---"), indent.Replace("-", "----") };
output = indents[indentCount] + stringToBeIndented;      

2

我没有足够的代表评论亚当的答案,但是imo的最佳方法是这样的:

public static string RepeatString(string content, int numTimes) {
        if(!string.IsNullOrEmpty(content) && numTimes > 0) {
            StringBuilder builder = new StringBuilder(content.Length * numTimes);

            for(int i = 0; i < numTimes; i++) builder.Append(content);

            return builder.ToString();
        }

        return string.Empty;
    }

您必须检查numTimes是否大于零,否则将获得异常。


2

我没有看到这个解决方案。对于目前在软件开发中的位置,我发现它更简单:

public static void PrintFigure(int shapeSize)
{
    string figure = "\\/";
    for (int loopTwo = 1; loopTwo <= shapeSize - 1; loopTwo++)
    {
        Console.Write($"{figure}");
    }
}

2

对于一般用途,涉及StringBuilder类的解决方案最适合重复多字符字符串。它经过优化,可以处理简单的串联无法实现的大量字符串的组合,而手工连接将很难或不可能高效地进行。此处显示的StringBuilder解决方案使用O(N)迭代来完成,此固定比率与重复的次数成正比。

但是,对于大量重复,或必须从中挤出高效率的情况,一种更好的方法是执行类似于StringBuilder基本功能的操作,但要从目标而不是从原始字符串中产生其他副本,如下。

    public static string Repeat_CharArray_LogN(this string str, int times)
    {
        int limit = (int)Math.Log(times, 2);
        char[] buffer = new char[str.Length * times];
        int width = str.Length;
        Array.Copy(str.ToCharArray(), buffer, width);

        for (int index = 0; index < limit; index++)
        {
            Array.Copy(buffer, 0, buffer, width, width);
            width *= 2;
        }
        Array.Copy(buffer, 0, buffer, width, str.Length * times - width);

        return new string(buffer);
    }

这样,每次迭代都会使源/目标字符串的长度加倍,从而节省了每次通过原始字符串时重置计数器的开销,而无需平滑地读取并复制现在更长的字符串,这是现代处理器可以做的事情更有效率。

它使用以2为底的对数来查找需要将字符串长度加倍的次数,然后进行多次。由于现在要复制的其余部分小于要复制的总长度,因此它可以简单地复制已生成内容的子集。

我已经在使用StringBuilder时使用了Array.Copy()方法,因为将StringBuilder的内容复制到自身中会产生开销,每次迭代都会产生一个包含该内容的新字符串。Array.Copy()避免了这种情况,同时仍然以极高的效率运行。

该解决方案需要O(1 + log N)次迭代才能完成,该速率与重复次数成对数增加(重复次数增加一倍等于一个额外的迭代),与其他方法相比节省了大量资金,而其他方法则按比例增加。


1

另一种方法是考虑string作为 IEnumerable<char>和有一个通用的扩展方法,这将通过指定的系数乘以一个集合中的项目。

public static IEnumerable<T> Repeat<T>(this IEnumerable<T> source, int times)
{
    source = source.ToArray();
    return Enumerable.Range(0, times).SelectMany(_ => source);
}

因此,在您的情况下:

string indent = "---";
var f = string.Concat(indent.Repeat(0)); //.NET 4 required
//or
var g = new string(indent.Repeat(5).ToArray());

1

重复打印一行。

Console.Write(new string('=', 30) + "\n");

=============================


为什么不使用Console.WriteLine而不是在字符串末尾附加\ n呢?
InxaneNinja

-1

您可以创建一个ExtensionMethod来做到这一点!

public static class StringExtension
{
  public static string Repeat(this string str, int count)
  {
    string ret = "";

    for (var x = 0; x < count; x++)
    {
      ret += str;
    }

    return ret;
  }
}

或使用@Dan Tao解决方案:

public static class StringExtension
{
  public static string Repeat(this string str, int count)
  {
    if (count == 0)
      return "";

    return string.Concat(Enumerable.Repeat(indent, N))
  }
}

3
看到我对Kyle的回答的评论
Thomas Levesque 2010年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.