C ++で文字列を可変回数繰り返す方法は?


127

C ++で文字列の先頭に「n」個のスペース(または任意の文字列)を挿入したい。std :: stringsまたはchar *文字列を使用してこれを行う直接的な方法はありますか?

たとえば、Pythonでは簡単にできます

>>> "." * 5 + "lolcat"
'.....lolcat'
c++ 

誰かがQStringを使用して回答を提供しますか?
Akiva

回答:


175

単一の文字を繰り返す特定のケースでは、以下を使用できますstd::string(size_type count, CharT ch)

std::string(5, '.') + "lolcat"

NB。これは、複数文字の文字列を繰り返すために使用することはできません。


79
OPは文字ではなく文字列の繰り返しを要求しました。
Florian Kaufmann

39

Python の*演算子またはPerlのx演算子に相当するC ++で文字列を繰り返す直接の慣用的な方法はありません。単一の文字を繰り返す場合、2つの引数を持つコンストラクター(前の回答で提案されているとおり)が適切に機能します。

std::string(5, '.')

これは、ostringstreamを使用して文字列をn回繰り返す方法の不自然な例です。

#include <sstream>

std::string repeat(int n) {
    std::ostringstream os;
    for(int i = 0; i < n; i++)
        os << "repeat";
    return os.str();
}

実装によっては、単に文字列をn回連結するよりも少し効率的かもしれません。


17

string :: insert:のいずれかの形式を使用します。

std::string str("lolcat");
str.insert(0, 5, '.');

これにより、文字列の先頭(位置0)に "....."(5つのドット)が挿入されます。


15
OPは文字ではなく文字列の繰り返しを要求しました。
ブレント

@Brent OPは、「 'n'スペース(または任意の文字列)」の両方を要求し、単一のピリオドを文字列として使用して、その意図を実証しました。英語は多くの人の第一言語ではないので、正確な要件を推測する必要がある場合があり、分析すると、質問は実際に単一の文字でこれを行う方法を尋ねます。私の回答が役に立たなかったので、反対票を投じる必要があったことを残念に思います。
camh

13

これは古い質問であることはわかっていますが、同じことをしたいと思っていましたが、私がより簡単な解決策だと思うものを見つけました。coutにはcout.fill()でこの関数が組み込まれているようです。「完全な」説明についてはリンクを参照してください

http://www.java-samples.com/showtutorial.php?tutorialid=458

cout.width(11);
cout.fill('.');
cout << "lolcat" << endl;

出力

.....lolcat

6
ドットのみ:最終行を...に変更cout << "" << endl;
musefan '11

9

OPが提供する例では、std :: stringのctorで十分ですstd::string(5, '.')。ただし、誰かがstd :: stringを複数回繰り返す関数を探している場合:

std::string repeat(const std::string& input, unsigned num)
{
    std::string ret;
    ret.reserve(input.size() * num);
    while (num--)
        ret += input;
    return ret;
}

8

Jaegerコモドールがほのめかしたように、私は他の答えのどれも実際にこの質問に答えるとは思いません。質問では、文字ではなく文字列を繰り返す方法を尋ねます。

Commodoreの答えは正しいですが、非常に非効率的です。これはより高速な実装です。最初に文字列を指数関数的に増やすことで、コピー操作とメモリ割り当てを最小限に抑えるというアイデアです。

#include <string>
#include <cstddef>

std::string repeat(std::string str, const std::size_t n)
{
    if (n == 0) {
        str.clear();
        str.shrink_to_fit();
        return str;
    } else if (n == 1 || str.empty()) {
        return str;
    }
    const auto period = str.size();
    if (period == 1) {
        str.append(n - 1, str.front());
        return str;
    }
    str.reserve(period * n);
    std::size_t m {2};
    for (; m < n; m *= 2) str += str;
    str.append(str.c_str(), (n - (m / 2)) * period);
    return str;
}

またoperator*、Pythonバージョンに近いものを定義することもできます。

#include <utility>

std::string operator*(std::string str, std::size_t n)
{
    return repeat(std::move(str), n);
}

私のマシンでは、これはCommodoreによって提供される実装よりも約10倍速く、単純な「append n-1 times」ソリューションよりも約2倍速くなっています


あなたの実装は「コピーを最小化」しません。ことを覚え+=、あなたのためのループ内で内部的にもない、ある種のループがあるstr.size()反復を。str.size()外側のループが繰り返されるたびに大きくなるため、外側の各繰り返しの後に、内側のループはさらに多くの繰り返しを行う必要があります。あなたと素朴な「コピーn回」の実装では、合計で両方のコピーn * period文字が使用されます。あなたの実装は、初期のため、1回だけメモリ割り当てを行いreserveます。実装のプロファイリングはかなり小さくstrて大きなものnだったと思いますが、大きくもstr小さくもありませんn
Florian Kaufmann

@FlorianKaufmannなぜ私の答えを攻撃することを選んだのかわからない。しかし、「最小限のコピー」とは、「コピー操作」を意味します。少数の大きなブロックをコピーする方が(さまざまな理由で)多数の小さなブロックをコピーするよりも効率的であるという考えです。単純な方法よりも入力文字列に追加の割り当てを行わないようにする可能性があります。
Daniel

2
それは、あなたの解決策が素朴な解決策よりも効率の面ではるかに優れているというあなたの主張を私が信じていないことを述べているコメントでした。私の測定では、単純なソリューションと比較して、コードは小さい文字列と多くの繰り返しで高速ですが、長い文字列と少ない繰り返しでは遅くなります。いくつかの大きなブロックをコピーする方が、多くの小さなブロックをコピーするよりもパフォーマンスが高い理由をさまざまに説明するリンクを提供できますか?分岐予測が考えられます。CPUキャッシュに関しては、どのバリアントが推奨されるかわかりません。
Florian Kaufmann

@FlorianKaufmann 2つのアプローチのstr大小に大きな違いはありませんn。これは、分岐予測自体よりもパイプライン全体に関係していると思います。考慮すべきデータ配置の問題もあります。これがプロセッサ/メモリフレンドリーである理由の詳細について、新しい質問をする必要があります。きっと多くの関心を集め、私がここで提供できるよりも優れた答えを受け取るでしょう。
Daniel

1
@FlorianKaufmann:x86では、rep movsb少なくとも中規模から大規模のコピーの場合、最も効率的なコピー方法の1つです。そのマイクロコード化された実装には、ほぼ一定の起動オーバーヘッド(AMDとIntelの両方)があります。たとえば、Sandybridgeでは、15から40サイクル、さらに64Bキャッシュラインあたり4サイクル(ベストケース)です。小さなコピーの場合は、起動のオーバーヘッドがないため、SSEループが最適です。しかし、それはブランチの誤予測の影響を受けます。
Peter Cordes、2016年


5

ITNOA

これにはC ++関数を使用できます。

 std::string repeat(const std::string& input, size_t num)
 {
    std::ostringstream os;
    std::fill_n(std::ostream_iterator<std::string>(os), num, input);
    return os.str();
 }

1
「ITNOA」とは一体どういう意味ですか?オンラインでの参照が見つかりません。
Folling
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.