【问题标题】:string Multiplication in C++C++中的字符串乘法
【发布时间】:2016-02-19 13:39:07
【问题描述】:

这里已经有一个问题:How to repeat a string a variable number of times in C++? 但是因为这个问题的表述很糟糕,所以给出了关于 character 乘法的主要答案。有两个正确但昂贵的答案,所以我将在这里提高要求。


Perl 提供了x 运算符:http://perldoc.perl.org/perlop.html#Multiplicative-Operators,它可以让我这样做:

$foo = "0, " x $bar;

我知道我可以使用其他答案中的辅助函数来执行此操作。我想知道我可以在没有自己的辅助功能的情况下做到这一点吗?我的偏好是我可以用它来初始化 const string,但如果我不能这样做,我很确定这可以用标准算法和 lambda 来回答。

【问题讨论】:

  • "标准算法和一个 lambda" - 怎么不是辅助函数?请说清楚。你想在这里实现什么目标?
  • @KarolyHorvath 我认为这些部分一起“在没有我自己的辅助函数的情况下执行此操作”-“如果我不能这样做,我很确定这可以通过标准算法和拉姆达“
  • 也许 op 想要为 std::string 自定义乘法运算符?
  • @KarolyHorvath 大多数链接的答案都是关于重复单个字符。只有one 是关于重复一个完整的字符串。我的回答是“真的很难看”“不必要的复杂”,我不觉得有任何冒犯,但您介意告诉我它们到底让您烦恼的是什么吗?链接的答案要复杂得多。
  • @KarolyHorvath 我也同意仅在一个地方使用 lambda 函数是不必要的。就地编写代码会容易得多。

标签: c++ string multiplication repeat


【解决方案1】:

您可以覆盖乘法运算符

#include <string>
#include <sstream>
#include <iostream>


std::string operator*(const std::string& str, size_t times)
{
    std::stringstream stream;
    for (size_t i = 0; i < times; i++) stream << str;
    return stream.str();
}

int main() {
    std::string s = "Hello World!";
    size_t times = 5;

    std::string repeated = s * times;
    std::cout << repeated << std::endl;

    return 0;
}

...或使用 lambda ...

#include <string>
#include <sstream>
#include <iostream>

int main() {
    std::string s = "Hello World!";
    size_t times = 5;

    std::string repeated = [](const std::string& str, size_t times) {std::stringstream stream; for (size_t i = 0; i < times; i++) stream << str; return stream.str(); } (s, times);
    std::cout << repeated << std::endl;

    return 0;
}

...或使用带有引用捕获的 lambda ...

#include <string>
#include <sstream>
#include <iostream>

int main() {
    std::string s = "Hello World!";
    size_t times = 5;

    std::string repeated = [&s, &times]() {std::stringstream stream; for (size_t i = 0; i < times; i++) stream << str; return stream.str(); }();
    std::cout << repeated << std::endl;

    return 0;
}

您也可以将std::stringstd::string::reserve(size_t) 结合使用,而不是使用std::stringstream,因为您已经知道(或可以计算)结果字符串的大小。

std::string repeated; repeated.reserve(str.size() * times);
for (size_t i = 0; i < times; i++) repeated.append(str);
return repeated;

这可能更快:比较 http://goo.gl/92hH9Mhttp://goo.gl/zkgK4T

【讨论】:

    【解决方案2】:

    可以仅使用标准算法和带有generate_n 的lambda 来执行此操作,但它仍然无法初始化const string,它需要在单独的行中完成:

    string foo;
    const auto bar = 13U;
    
    generate_n(back_inserter(foo), bar * 3U, [](){
        static const char multiplicand[] = "0, ";
        static const auto length = strlen(multiplicand);
        static auto i = 0U;
        return multiplicand[i++ % length];});
    

    我在这里创建了一个实时示例:http://ideone.com/uIt2Ee 但正如所有问题 cmets 可能都清楚的那样,在一行中执行此操作的要求导致代码质量较差。马上,我们可以看到裸常量3 表示multiplicand 的大小,并且不必要地需要更改multiplicand 的初始化来更新这个字面量。

    应该做的明显改进是:

    string foo;
    const auto bar = 13U;
    const char multiplicand[] = "0, ";
    const auto length = strlen(multiplicand);
    
    generate_n(back_inserter(foo), bar * length, [&](){
        static auto i = 0U;
        return multiplicand[i++ % length];
    });
    

    下一个改进将是在foo 增长时消除重新分配,如果barlength 很大,这可能会很昂贵。这可以通过构造foo 来实现,该foo 具有足够的空间来包含整个生成的字符串:

    const auto bar = 13U;
    const char multiplicand[] = "0, ";
    const auto length = strlen(multiplicand);
    string foo(bar * length, '\0');
    
    generate_n(foo.begin(), bar * length, [&](){
        static auto i = 0U;
        return multiplicand[i++ % length];
    });
    

    [Live Example]

    【讨论】:

    • string::reserve 而不是在构造时调整大小将避免初始化foo 两次。
    • @Jarod42 嗯...我不打电话给reserveresize。你是在说我callocs foo: string foo(bar * length, '\0');的构造论点吗?
    • 是的,我谈到了string foo(bar * length, '\0')。将替换为string foo; foo.reserve(bar * length);
    • @Jarod42 我不确定我是否理解为什么它不比calloc 更可取。这不会导致foo 成为malloced,然后是realloced,因为string 必须始终包含至少1 个char(终止NULL。)
    • 还有小的字符串优化,所以我希望reserve 只分配一个。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多