我可以“乘以”一个字符串(在C#中)吗?


136

假设我有一个字符串,例如

string snip =  "</li></ul>";

我想基本上将它多次写入,具体取决于某个整数值。

string snip =  "</li></ul>";
int multiplier = 2;

// TODO: magic code to do this 
// snip * multiplier = "</li></ul></li></ul>";

编辑:我知道我可以很容易地编写自己的函数来实现这一点,我只是想知道是否有一些我不知道的奇怪的字符串运算符


Answers:


222

在.NET 4中,您可以执行以下操作:

String.Concat(Enumerable.Repeat("Hello", 4))

9
在.NET 3.5中,它的功能不多:String.Concat(Enumerable.Repeat(“ Hello”,4).ToArray())
Mark Foreman

4
我不觉得这很优雅。在python中,执行此操作的代码是:snip * multiplier(这并不可怕..但也不是很漂亮)。
痴呆的刺猬

7
@dementedhedgehog我知道您承认自己的痴呆症,但是即使您遭受痛苦,您也可能会发现Python示例对C#问题的回答不是很好...我想我们大多数人都可以看到语言选择始终是一种折衷方案,对任何问题的几乎所有答案都可以在倡导者的支持下加注,无论是赞成还是反对。
Will Dean

1
@will dean:我只是指Matthew Nichols关于您所拥有代码优雅的声明。据我所知,就此问题而言,您的代码对于C#而言是优雅的。我要提出的要点是:(我相信)扩展C#以重载*运算符以允许int *字符串乘法将非常容易(对于Microsoft,因为字符串是密封的)。那么从某种普遍意义上讲,它实际上是优雅的,恕我直言,而不仅仅是在目前存在的C#所施加的约束条件下优雅。
痴呆的刺猬

@dementedhedgehog对我来说,这与二进制operator*表示的含义相反。我猜对每个人来说。
TEK

99

请注意,如果您的“字符串”仅是一个字符,则字符串构造函数将对其进行重载:

int multipler = 10;
string TenAs = new string ('A', multipler);

这真的很亲。
Zaven Zareyan '19

61

不幸的/幸运的是,字符串类是密封的,因此您不能从它继承并重载*运算符。您可以通过以下方式创建扩展方法:

public static string Multiply(this string source, int multiplier)
{
   StringBuilder sb = new StringBuilder(multiplier * source.Length);
   for (int i = 0; i < multiplier; i++)
   {
       sb.Append(source);
   }

   return sb.ToString();
}

string s = "</li></ul>".Multiply(10);

5
就在我要去的地方!您可以通过在StringBuilder ctor中使用source.Length *乘数进行优化
Marc Gravell

2
Marc的评论正是要去的地方:)
Jon Skeet

1
您需要(source.Length *乘数),而不仅仅是(乘数)
Marc Gravell

1
非常确定。它在幕后分配一个(该长度的)字符串,然后对其进行变异。它像一个普通的List <T>等不工作
马克·Gravell

1
扩展方法在这里是理想的。
克里斯·巴伦斯

12

我与DrJokepu在一起,但是如果由于某些原因您确实想使用内置功能作弊,则可以执行以下操作:

string snip = "</li></ul>";
int multiplier = 2;

string result = string.Join(snip, new string[multiplier + 1]);

或者,如果您使用的是.NET 4:

string result = string.Concat(Enumerable.Repeat(snip, multiplier));

就我个人而言,我不会打扰-自定义扩展方法要好得多。


1
我从来不知道有这样的作弊。=)
詹妮妮

10

仅出于完整性考虑,这是另一种方法:

public static string Repeat(this string s, int count)
{
    var _s = new System.Text.StringBuilder().Insert(0, s, count).ToString();
    return _s;
}

我想我前段时间从Stack Overflow中拉了那个,所以这不是我的主意。


9

您必须编写一个方法-当然,对于C#3.0,它可能是扩展方法:

public static string Repeat(this string, int count) {
    /* StringBuilder etc */ }

然后:

string bar = "abc";
string foo = bar.Repeat(2);

.NET3甚至没有Enumerable.Repeat吗?
Will Dean 2010年

@Will-.NET 3是WCF / WPF等,所以没有;它确实存在于.NET 3.5中,但是随后您也需要string.Join它-为什么不循环n次?更直接。
马克·格雷韦尔

谢谢-我没有正确考虑3.0与3.5。至于为什么不仅仅使用循环,那么这肯定是功能性与命令性辩论的全部实质吗?我发布了一个.net 4答案,我认为这在“功能性聪明”与“循环显而易见性”的辩论中还算不错。
Will Dean 2010年

8

有点晚了(只是为了好玩),如果您真的想使用*运算符来完成这项工作,可以这样做:

public class StringWrap
{
    private string value;
    public StringWrap(string v)
    {
        this.value = v;
    }
    public static string operator *(StringWrap s, int n)
    {
        return s.value.Multiply(n); // DrJokepu extension
    }
}

所以:

var newStr = new StringWrap("TO_REPEAT") * 5;

需要注意的是,只要你能找到一个合理的行为,对他们来说,也可以通过处理其他运营商StringWrap类,如\^%等...

PS:

Multiply()@DrJokepu的扩展信用保留所有权利;-)


7

这更加简洁:

new StringBuilder().Insert(0, "</li></ul>", count).ToString()

using System.Text;在这种情况下,应导入名称空间。


2
string Multiply(string input, int times)
{
     StringBuilder sb = new StringBuilder(input.length * times);
     for (int i = 0; i < times; i++)
     {
          sb.Append(input);
     }
     return sb.ToString();
}

2

如果您拥有.Net 3.5而不是4.0,则可以使用System.Linq

String.Concat(Enumerable.Range(0, 4).Select(_ => "Hello").ToArray())

要获得一个字符串你仍然需要String.Concat,而在3.5上你也需要.ToArray()。恐怕不是最优雅的解决方案。
科比

2

由于每个人都在添加他们自己的.NET4 / Linq示例,所以我不妨添加自己的示例。(基本上,它是DrJokepu的,减少到单线)

public static string Multiply(this string source, int multiplier) 
{ 
    return Enumerable.Range(1,multiplier)
             .Aggregate(new StringBuilder(multiplier*source.Length), 
                   (sb, n)=>sb.Append(source))
             .ToString();
}

0

好吧,这是我的看法:

public static class ExtensionMethods {
  public static string Multiply(this string text, int count)
  {
    return new string(Enumerable.Repeat(text, count)
      .SelectMany(s => s.ToCharArray()).ToArray());
  }
}

我当然有点傻,但是当我需要在代码生成类中使用制表时,Enumerable.Repeat会为我做这件事。是的,StringBuilder版本也很好。


0

这是我的看法,仅供将来参考:

    /// <summary>
    /// Repeats a System.String instance by the number of times specified;
    /// Each copy of thisString is separated by a separator
    /// </summary>
    /// <param name="thisString">
    /// The current string to be repeated
    /// </param>
    /// <param name="separator">
    /// Separator in between copies of thisString
    /// </param>
    /// <param name="repeatTimes">
    /// The number of times thisString is repeated</param>
    /// <returns>
    /// A repeated copy of thisString by repeatTimes times 
    /// and separated by the separator
    /// </returns>
    public static string Repeat(this string thisString, string separator, int repeatTimes) {
        return string.Join(separator, ParallelEnumerable.Repeat(thisString, repeatTimes));
    }

希望您不要ParallelEnumerable在这种情况下使用。string.Join需要按顺序使用元素,因此不需要并行生成它们。
加布

@Gabe:由于项目是相同的,并且实际上只是thisString的副本,所以我不必担心这里的顺序。
Jronny

我同意该领域的许多老师的看法,通常最好对您的意思进行编码。毫无疑问地说您想要并行处理,而只是暗自认为“嗯,我知道无论如何在这种情况下都不会并行处理”
sehe 2011年

我认为将其并行会使其更快,或者请启发我。这就是为什么我将其转换为ParallelEnumerable的原因,因此我认为我的代码在说我的意思...谢谢。
Jronny
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.