文字列を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まで、オーバーロードされたStringクラスのコンストラクターは、受け入れられた回答を完全に適合させる可能性のある繰り返しを作成するためのパラメーターとして文字列を取りません。
RBT

回答:


538

同じ文字を繰り返すだけの場合は、charを受け入れる文字列コンストラクタと、その文字を繰り返す回数を使用できますnew String(char c, int count)

たとえば、ダッシュを5回繰り返すには:

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

8
この小さな機能について思い出させてくれてありがとう。それは私の心の隅で失われたと思います。
Chris Shouts

3
タブのメタ文字「\ t」は文字なので、インデントにも使用できます。
cori

91
これはC#の非常に便利なトリックですが、質問のタイトルは(charではなく)文字列について尋ねています。これより下の他の回答は実際には質問に回答していますが、評価ははるかに低くなっています。私はアフマドの答えを軽視しようとはしていませんが、この質問のタイトルを変更する必要がある(質問が実際にキャラクターに関するものである場合)か、他の回答を実際に賛成する必要があります(これではありません)。
pghprogrammer4 2013年

14
@Ahmad言ったように、あなたが良い情報を提供したとは思わないので、私は反対票を投じませんでしたが、あなたが提供した情報は、現在述べられている質問への回答とは無関係です。文字列(文字ではなく)を繰り返す方法を探していて、関連する質問に到達したときに、いくつかの「便利な」ヒントをスクロールして、質問に対する実際の回答を得る必要がある場合を想像してみてください。反対票があなたに不快な場合は、削除できます。しかし、私がどこから来たのかわかりますか?私は完全にここから外れていますか?
pghprogrammer4 2013年

11
@ pghprogrammer4 IMHO、反対投票はかなり期待を裏切る可能性があり、重大な変更が必要であるか、作成者が削除する必要がある、有害/誤解を招く/ truly_badの回答にのみ使用する必要があります。人々が寛大であり、彼らが知っていることを共有したいので、答えが存在します。一般的に、これらのサイトは実際にトップに有用な答えをもたらすために賛成投票を奨励しています。
ToolmakerSteve 2014年

271

.NET 4.0を使用string.ConcatしてEnumerable.Repeatいる場合は、と一緒に使用できます。

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

そうでなければ、私はアダムの答えのようなもので行きます

私が一般的にAndreyの回答を使用することを勧めない理由は、呼び出しが、Adamによって提案されたアプローチで回避される余分なオーバーヘッドを導入するというだけです。つまり、少なくとも.NET 4.0を必要とせずに機能します。そして、それは速くて簡単です(そして、効率があまり気にならなければあなたを殺すつもりはありません)。ToArray()StringBuilder


3
これは文字列でうまく機能します-改行しないスペース( )を連結する必要がある場合のように。しかし、charを処理している場合は、文字列コンストラクターが最も高速になると思います...
woodbase

1
文字列コンストラクタは1つの文字に対してのみ機能します。Concat Repeatを使用するオプションへの切り替えは文字列に対して機能します
Eli Dagan

4
タイトルの実際の質問にお答えいただきありがとうございます。
Mark K Cowan

私はこの答えが好きです!
Ji_in_coding

-System.Linq.Enumerableなどを出力として取得している場合は、スニペットをコピー/貼り付けおよび変更するのが速すぎたためです。あなたがEnumerable.Repeatの出力に異なる文字列をCONCATする必要がある場合、あなたはこのようにそれを実行する必要があります Console.WriteLine(string.Concat("-", string.Concat(Enumerable.Repeat(indent, N))));
ゲイブ

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、コードの透過性が低くなるとは想像できません。
Adam Robinson、

@dtb:ああ。StringBuilderを使用します。これを効率的に行うように設計されています。
ToolmakerSteve 2014年

アダム、あなたはカウントに追加するときにnullの入力をテストするという問題に遭遇したのを見ましたが、それが失敗するのを許し、Appendがnullを与えられて何もしないことに頼っていました。私見これは明白ではありません:nullが考えられる入力である場合、その前にテストして空の文字列を返してみませんか?
ToolmakerSteve 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ストレージの事前割り当てによる効率的な使用。

私は同意します、これは素晴らしいです。私はこれをボブへのクレジットで私のコードに追加しました!ありがとう!
John Burley

22

目的の文字列に単一の文字しか含まれていない場合は、String.PadLeftを使用します。

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

クレジットはこちら


1
接吻。とにかく、何のためにStringBuildersと拡張機能が必要ですか?これは非常に単純な問題です。
DOK

1
私は知らない、これはいくつかの優雅さで表現された問題を解決するようです。そして、ところで、あなたは誰を「S」と呼んでいますか?:-)
スティーブタウンゼント

7
しかし、これは本当に、a aをとるコンストラクタのあまり目立たないバージョンではありstringcharintませんか?
Dan Tao

""の代わりにString.Emptyを使用すると、見栄えがよくなります。それ以外の場合は、良い解決策です;)
Thomas Levesque

@Steve BTW String.PadLeft引数は逆になります。countパディング文字の前に来ます。
Ahmad Mageed

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

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より前のバージョンでは、そうする必要があると思います。
Dan Tao

3

私は与えられた答えが好きです。同じ行に沿って私は過去に使用したものですが:

"" .PadLeft(3 * Indent、 '-')

これはインデントの作成を満たしますが、技術的には文字列を繰り返すことが問題でした。文字列インデントが>-<のようなものである場合、これと受け入れられた回答は機能しません。この場合、stringbuilderを使用したc0rdのソリューションは良さそうですが、stringbuilderのオーバーヘッドが実際には最もパフォーマンスが高くない場合があります。1つのオプションは、文字列の配列を作成し、それをインデント文字列で埋めてから連結することです。聖霊降臨祭に:

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 2013年

1
パラメータ@thisに名前を付けることについて、昔ながらのことは何もありません。それは常に恐ろしい考え
でした

2
強制されない限り、変数名としてキーワードを使用したくない(CSSを参照するクラスが必要なため、MVCを使用する場合は@class = "something"など)。これは、C#のキーワードです(もちろん、これだけではありません)。それは一般的な経験則です。これは確かにコンパイル可能コードであり正当ですが、どちらも読みやすさと入力のしやすさを考慮してください。どちらも実用的な理由です。最初に何が起こっているのかを説明するためにパラメータ名を使用するのは非常に部分的なので、Repeat(この文字列シード、 int型の数)より説明の私見であるかもしれない。
デイブJellison

1
興味深い、ありがとう。この場合、@ thisは説明よりも説明が少ないと思います。ただし、一般に、クラスまたはインターフェイスを拡張することは非常に一般的であり、「this」の唯一の妥当な名前はかなり一般的です。'instance'、 'it'、または 'str'(MSDNを参照)というパラメーターがある場合、おそらくこれは 'this'です。
OlduwanSteve 2013年

1
基本的に私はあなたに同意しますが、議論のために...私が構築している文字列についてもっと知っているので、私はStringBuilderよりもわずかに良い仕事をすることができます。StringBuilderは、メモリを割り当てるときに推測する必要があります。多くのシナリオでそれが問題になる可能性は低いと考えられますが、誰かが膨大な数の繰り返し文字列を並行して構築し、数クロックサイクル戻って喜んでいるかもしれません:)
OlduwanSteve

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

Adamの回答にコメントするのに十分な担当者がいませんが、それを行う最善の方法は次のとおりです。

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倍になり、元の文字列を通過するたびにカウンターをリセットするオーバーヘッドが節約され、現在のより長い文字列をスムーズに読み取ってコピーできるようになりました。より効率的に。

これは、2を底とする対数を使用して、文字列の長さを2倍にする必要がある回数を検出し、その回数だけ計算を続けます。コピーされる残りの部分は、コピー元の全長より短いので、すでに生成されているもののサブセットをコピーするだけで済みます。

StringBuilderを使用してArray.Copy()メソッドを使用しました。これは、StringBuilderのコンテンツをそれ自体にコピーすると、そのコンテンツで新しい文字列を生成するたびにオーバーヘッドが発生するためです。Array.Copy()はこれを回避しながら、非常に高い効率で動作します。

このソリューションは、完了するまでにO(1 + log N)の反復を必要とします。これは、反復回数に応じて対数的に増加するレートです(反復回数を2倍にすると、追加の反復が1回になります)。他の方法よりも大幅に節約でき、比例して増加します。


1

別のアプローチは、コレクション内のアイテムに指定された係数を掛ける一般的な拡張メソッドと見なしstringIEnumerable<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");

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


文字列の最後に\ nを追加する代わりに、Console.WriteLineを使用しなかったのはなぜですか?
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
カイルの回答に対する私のコメントを参照してください
トーマス・レベスク
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.