Làm thế nào để lặp lại một chuỗi số lần thay đổi trong C ++?


127

Tôi muốn chèn khoảng trắng (hoặc bất kỳ chuỗi nào) vào đầu chuỗi trong C ++. Có cách nào trực tiếp để làm điều này bằng cách sử dụng chuỗi std :: chuỗi hoặc char * không?

Ví dụ, trong Python bạn chỉ cần làm

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

Ai đó cung cấp câu trả lời bằng cách sử dụng QString?
Akiva

Câu trả lời:


175

Trong trường hợp cụ thể lặp lại một ký tự, bạn có thể sử dụng std::string(size_type count, CharT ch):

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

Lưu ý Điều này không thể được sử dụng để lặp lại chuỗi nhiều ký tự.


79
OP yêu cầu lặp lại một chuỗi, không phải là một ký tự.
Florian Kaufmann

39

Không có cách thành ngữ trực tiếp để lặp lại các chuỗi trong C ++ tương đương với toán tử * trong Python hoặc toán tử x trong Perl. Nếu bạn đang lặp lại một ký tự, hàm tạo hai đối số (như được đề xuất bởi các câu trả lời trước) hoạt động tốt:

std::string(5, '.')

Đây là một ví dụ giả định về cách bạn có thể sử dụng một đường truyền để lặp lại một chuỗi n lần:

#include <sstream>

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

Tùy thuộc vào việc thực hiện, điều này có thể hiệu quả hơn một chút so với việc đơn giản nối chuỗi n lần.


17

Sử dụng một trong các dạng của chuỗi :: insert:

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

Điều này sẽ chèn "....." (năm dấu chấm) ở đầu chuỗi (vị trí 0).


15
OP yêu cầu lặp lại một chuỗi, không phải là một ký tự.
Brent

@Brent OP yêu cầu cả hai - "'n' khoảng trắng (hoặc bất kỳ chuỗi nào)", và sau đó tiếp tục thể hiện ý định của họ với một khoảng thời gian duy nhất là chuỗi. Tiếng Anh không phải là ngôn ngữ đầu tiên của nhiều người, vì vậy đôi khi bạn cần đoán chính xác các yêu cầu của họ và khi phân tích, câu hỏi thực sự là làm thế nào để làm điều này với một ký tự duy nhất. Tôi xin lỗi bạn đã tìm thấy câu trả lời của tôi đủ hữu ích mà bạn cần phải bỏ phiếu.
camh

13

Tôi biết đây là một câu hỏi cũ, nhưng tôi đang tìm cách làm điều tương tự và đã tìm thấy những gì tôi nghĩ là một giải pháp đơn giản hơn. Dường như cout có chức năng này được tích hợp với cout.fill (), hãy xem liên kết để được giải thích 'đầy đủ'

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

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

đầu ra

.....lolcat

6
chỉ dấu chấm: thay đổi dòng cuối cùng thành ...cout << "" << endl;
musefan

9

Đối với các mục đích của ví dụ được cung cấp bởi OP std :: string's ctor là đủ : std::string(5, '.'). Tuy nhiên, nếu bất cứ ai đang tìm kiếm một hàm để lặp lại std :: chuỗi nhiều lần:

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

8

Như Commodore Jaeger đã ám chỉ, tôi không nghĩ bất kỳ câu trả lời nào khác thực sự trả lời câu hỏi này; câu hỏi hỏi làm thế nào để lặp lại một chuỗi, không phải là một ký tự.

Trong khi câu trả lời được đưa ra bởi Commodore là chính xác, nó khá kém hiệu quả. Đây là một triển khai nhanh hơn, ý tưởng là để giảm thiểu các hoạt động sao chép và phân bổ bộ nhớ bằng cách tăng chuỗi theo cấp số nhân:

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

Chúng ta cũng có thể định nghĩa operator*để có được một cái gì đó gần hơn với phiên bản Python:

#include <utility>

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

Trên máy tính của tôi, tốc độ này nhanh hơn khoảng 10 lần so với triển khai do Commodore đưa ra và nhanh hơn khoảng 2 lần so với giải pháp 'nối thêm n - 1 lần' ngây thơ .


Việc triển khai của bạn không "giảm thiểu sao chép". Lưu ý rằng +=bên trong vòng lặp for của bạn bên trong cũng có một vòng lặp nào đó str.size()lặp đi lặp lại. str.size()phát triển trong mỗi lần lặp bên ngoài, vì vậy sau mỗi lần lặp bên ngoài, vòng lặp bên trong phải thực hiện nhiều lần lặp hơn. Việc thực hiện 'sao chép n lần' của bạn và ngây thơ trong tổng số cả hai n * periodký tự sao chép . Việc triển khai của bạn chỉ thực hiện một cấp phát bộ nhớ vì ban đầu reserve. Tôi đoán bạn đã mô tả thực hiện của bạn với một khá nhỏ strvà lớn n, nhưng cũng không phải với lớn strvà nhỏ n.
Florian Kaufmann

@FlorianKaufmann Không chắc tại sao bạn lại chọn tấn công câu trả lời của tôi. Nhưng bằng cách "giảm thiểu sao chép", ý tôi là "sao chép hoạt động". Ý tưởng là sao chép một số lượng nhỏ các khối lớn sẽ hiệu quả hơn (vì nhiều lý do) hơn là sao chép một số lượng lớn các khối nhỏ. Tôi có khả năng tránh phân bổ bổ sung cho chuỗi đầu vào so với phương thức ngây thơ.
Daniel

2
Đó là một bình luận nói rằng tôi không tin rằng tuyên bố của bạn về mặt hiệu quả tốt hơn nhiều so với giải pháp ngây thơ. Trong các phép đo của tôi, so với giải pháp ngây thơ, mã của bạn nhanh hơn với các chuỗi nhỏ và nhiều lần lặp lại, nhưng chậm hơn với các chuỗi dài và một vài lần lặp lại. Bạn có thể cung cấp các liên kết giải thích chi tiết hơn về nhiều lý do tại sao sao chép một vài khối lớn có hiệu suất cao hơn so với sao chép nhiều khối nhỏ? Tôi có thể nghĩ về dự đoán chi nhánh. Về bộ đệm CPU tôi không chắc chắn biến thể nào được ưa thích.
Florian Kaufmann

@FlorianKaufmann Tôi thấy không có sự khác biệt đáng kể nào giữa lớn strvà nhỏ ngiữa hai cách tiếp cận. Tôi tin rằng điều này có liên quan nhiều đến đường ống tổng thể hơn dự đoán chi nhánh, cũng có vấn đề căn chỉnh dữ liệu để xem xét. Bạn nên hỏi một câu hỏi mới để biết chi tiết về lý do tại sao điều này thân thiện với bộ xử lý / bộ nhớ hơn, tôi chắc chắn rằng nó sẽ thu hút được nhiều sự quan tâm và nhận được câu trả lời tốt hơn tôi có thể đưa ra ở đây.
Daniel

1
@FlorianKaufmann: Trên x86, rep movsblà một trong những cách hiệu quả nhất để sao chép, ít nhất là cho các bản sao từ trung bình đến lớn. Việc triển khai mã hóa vi mô của nó có một số chi phí khởi động gần như không đổi (trên cả AMD và Intel), ví dụ như trên Sandybridge, ~ 15 đến 40 chu kỳ, cộng với 4 chu kỳ trên mỗi dòng bộ đệm 64B (trường hợp tốt nhất) . Đối với các bản sao nhỏ, vòng lặp SSE là tốt nhất vì nó không có chi phí khởi động. Nhưng sau đó, nó có thể bị đánh giá sai chi nhánh.
Peter Cordes


5

ITNOA

Bạn có thể sử dụng chức năng C ++ để làm việc này.

 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" trên trái đất có nghĩa là gì? Không thể tìm thấy bất kỳ tài liệu tham khảo trực tuyến.
Theo dõi
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.