Bagaimana cara mengulang string beberapa kali dalam C ++?


127

Saya ingin memasukkan spasi 'n' (atau string apa pun) di awal string di C ++. Apakah ada cara langsung untuk melakukan ini menggunakan std :: strings atau char * string?

Misalnya dengan Python Anda bisa melakukannya

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

Seseorang memberikan jawaban menggunakan QString?
Akiva

Jawaban:



39

Tidak ada cara idiomatik langsung untuk mengulang string dalam C ++ yang setara dengan operator * di Python atau operator x di Perl. Jika Anda mengulangi satu karakter, konstruktor dua argumen (seperti yang disarankan oleh jawaban sebelumnya) berfungsi dengan baik:

std::string(5, '.')

Ini adalah contoh buatan bagaimana Anda dapat menggunakan ostringstream untuk mengulang string sebanyak n kali:

#include <sstream>

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

Bergantung pada implementasinya, ini mungkin sedikit lebih efisien daripada sekadar menggabungkan string sebanyak n kali.


17

Gunakan salah satu bentuk string :: insert:

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

Ini akan memasukkan "....." (lima titik) di awal string (posisi 0).


16
OP meminta pengulangan string, bukan karakter.
Brent

@Brent OP meminta keduanya - "'n' spasi (atau string apa pun)", dan kemudian melanjutkan untuk menunjukkan maksud mereka dengan satu titik sebagai string. Bahasa Inggris bukanlah bahasa pertama banyak orang sehingga Anda terkadang perlu menebak dengan tepat persyaratan mereka dan ketika dianalisis, pertanyaannya sebenarnya menanyakan bagaimana melakukan ini dengan satu karakter. Saya minta maaf karena Anda menganggap jawaban saya tidak cukup membantu sehingga Anda perlu menolaknya.
camh

13

Saya tahu ini adalah pertanyaan lama, tetapi saya ingin melakukan hal yang sama dan menemukan apa yang menurut saya merupakan solusi yang lebih sederhana. Tampaknya cout memiliki fungsi ini bawaan dengan cout.fill (), lihat tautan untuk penjelasan 'lengkap'

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

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

keluaran

.....lolcat

6
hanya titik: ubah baris terakhir menjadi ...cout << "" << endl;
musefan

9

Untuk keperluan contoh yang diberikan oleh OP std :: ctor string cukup: std::string(5, '.'). Namun, jika ada yang mencari fungsi untuk mengulang std :: string beberapa kali:

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

8

Seperti yang disinggung oleh Commodore Jaeger, saya rasa tidak ada jawaban lain yang benar-benar menjawab pertanyaan ini; pertanyaannya menanyakan bagaimana mengulang sebuah string, bukan karakter.

Meskipun jawaban yang diberikan oleh Commodore benar, itu cukup tidak efisien. Berikut adalah implementasi yang lebih cepat, idenya adalah untuk meminimalkan operasi penyalinan dan alokasi memori dengan terlebih dahulu mengembangkan string secara eksponensial:

#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;
}

Kita juga dapat mendefinisikan operator*untuk mendekati versi Python:

#include <utility>

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

Di komputer saya, ini sekitar 10x lebih cepat daripada implementasi yang diberikan oleh Commodore, dan sekitar 2x lebih cepat daripada solusi naif 'tambahkan n - 1 kali' .


Penerapan Anda tidak 'meminimalkan penyalinan'. Ingatlah bahwa +=dalam loop for Anda secara internal juga memiliki semacam loop yang melakukan str.size()iterasi. str.size()tumbuh di setiap iterasi loop luar, jadi setelah setiap iterasi luar, loop dalam harus melakukan lebih banyak iterasi. Anda dan implementasi 'salin n kali' naif secara total kedua n * periodkarakter salin . Implementasi Anda hanya melakukan satu alokasi memori karena inisial reserve. Saya kira Anda memprofilkan implementasi Anda dengan yang agak kecil strdan besar n, tetapi tidak juga dengan besar strdan kecil n.
Florian Kaufmann

@FlorianKaufmann Tidak yakin mengapa Anda memilih untuk menyerang jawaban saya. Tetapi dengan "meminimalkan penyalinan" yang saya maksud adalah 'operasi penyalinan'. Idenya adalah bahwa menyalin sejumlah kecil blok besar lebih efisien (karena berbagai alasan) daripada menyalin sejumlah besar blok kecil. Saya berpotensi menghindari alokasi tambahan pada string input melalui metode naif.
Daniel

2
Itu adalah komentar yang menyatakan bahwa saya tidak percaya klaim Anda bahwa solusi Anda jauh lebih baik dalam hal efisiensi daripada solusi naif. Dalam pengukuran saya, dibandingkan dengan solusi naif, kode Anda lebih cepat dengan string kecil dan banyak pengulangan, tetapi lebih lambat dengan string panjang dan sedikit pengulangan. Dapatkah Anda memberikan tautan yang menjelaskan secara lebih rinci berbagai alasan mengapa menyalin beberapa blok besar memiliki kinerja yang lebih tinggi daripada menyalin banyak blok kecil? Saya bisa memikirkan prediksi cabang. Mengenai cache CPU, saya tidak yakin varian mana yang lebih disukai.
Florian Kaufmann

@FlorianKaufmann Saya tidak melihat perbedaan yang signifikan untuk besar strdan kecil nantara kedua pendekatan tersebut. Saya yakin ini lebih berkaitan dengan keseluruhan pipa daripada prediksi cabang itu sendiri, ada juga masalah penyelarasan data yang perlu dipertimbangkan. Anda harus mengajukan pertanyaan baru untuk perincian mengapa ini lebih ramah prosesor / memori, saya yakin ini akan menarik banyak minat, dan menerima jawaban yang lebih baik daripada yang bisa saya berikan di sini.
Daniel

1
@FlorianKaufmann: Pada x86, rep movsb adalah salah satu cara paling efisien untuk menyalin, setidaknya untuk salinan berukuran sedang hingga besar. Implementasi kode mikro-nya memiliki beberapa overhead startup yang hampir konstan (pada AMD dan Intel), misalnya pada Sandybridge, ~ 15 hingga 40 siklus, ditambah 4 siklus per baris cache 64B (kasus terbaik) . Untuk salinan kecil, loop SSE paling baik karena tidak memiliki overhead pengaktifan. Tapi kemudian itu tunduk pada kesalahan prediksi cabang.
Peter Cordes


5

ITNOA

Anda dapat menggunakan fungsi C ++ untuk melakukan ini.

 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
Apa artinya "ITNOA"? Tidak dapat menemukan referensi apa pun untuk itu secara online.
Folling
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.