快速多替换字符串

4

我有一个类似下面的字符串:

{A}jahshs{b}jwuw{c}wuqjwhaha{d}{e}{f}jsj{g}

我需要替换每个{x}为不同的字符串。问题在于这个过程将会每秒重复约1000次,所以我需要一种优化/快速的方法来完成它。

有任何想法吗?使用Boost replace?还是Boost format?等等。


1
std::string::replace,测量并证明它不够快? - Kerrek SB
但是我应该为字符串中的每个{x}调用replace,大约有10个。因此每秒进行10x1000次替换。 - Pepeluis
没有什么能够取代在你的端上进行测试和测量。有太多的变量。如果你编写了一些代码,但它仍然比你预期的要慢,我们至少可以查看你的代码并讨论。 - Anthony Kong
1个回答

0
  1. 预先分配所有缓冲区

    ....

  2. 获利

哦,不要垃圾邮件。样例代码在 5 10 分钟内发布。

好的,这里是:还有 Live On Coliru

#include <string>
#include <sstream>
#include <boost/utility/string_ref.hpp>

template <typename Range>
int expand(Range const& /*key*/)
{
    return rand()%42; // todo lookup value with key (be sure to stay lean here)
}

#include <iostream>
int main()
{
    static const std::string msg_template = "{A}jahshs{b}jwuw{c}wuqjwhaha{d}{e}{f}jsj{g}\n";

    std::ostringstream builder;
    builder.str().reserve(1024); // reserve ample room, not crucial since we reuse it anyways

    for (size_t iterations = 1ul << 14; iterations; --iterations)
    {
        builder.str("");
        std::ostreambuf_iterator<char> out(builder);

        for(auto f(msg_template.begin()), l(msg_template.end()); f != l;)
        {
            switch(*f)
            {
                case '{' : 
                    {
                        auto s = ++f;
                        size_t n = 0;

                        while (f!=l && *f != '}')
                            ++f, ++n;

                        // key is [s,f] now
                        builder << expand(boost::string_ref(&*s, n));

                        if (f!=l)
                            ++f; // skip '}'
                    }
                    break;
                default:
                    *out++ = *f++;
            }
        }
        // to make it slow, uncomment:
        // std::cout << builder.str();
    }
}

这在我的系统上运行时间约为0.239秒。 大约是每秒68k次扩展 哎呀,在发布版中,它每秒可进行400万个扩展。在Coliru上几乎能达到每秒100万次的扩展。

有改进的空间:

  • 您可以预先验证输入。
  • 如果您知道参数键始终为1个字母,则可以通过用char替换string_ref,并不循环处理'}'来简化代码。
  • 您可以预先计算参数索引并跳转到相应位置。但好处并不确定(某些处理器可以很好地顺序访问内存,并且幼稚的方法可能更快)。

每个 { x } 都是一个宏名称,要替换的内容可能会有所不同,此外主字符串也可能会有所不同。因此,这是一种宏扩展器。 - Pepeluis
是的?你运行了代码吗?有什么你无法理解的地方吗?你执行了expand函数吗?正如你所看到的,它是一种“宏扩展器”。我确保你可以返回任何可以进行IO流操作的东西。也许这个2行编辑会有所帮助 - sehe
这可以通过使insert_expanded接受构建器流而更加高效(http://coliru.stacked-crooked.com/a/be82fad7b1442787)轻松实现。一个模仿邮件合并的示例:http://coliru.stacked-crooked.com/a/cde6e91f3d898888 - sehe
哦,还有随机模板(“除了主字符串可能也会变化”)。最后但并非最不重要的:**这里有一个旧答案**,我使用Boost Spirit实现了一个更加多功能的宏扩展系统(即嵌套宏、转义宏字符、递归评估)。干杯 - sehe
恐怕那会是一个稍微冗长的话题。这些特性已经在那个答案和测试用例中有所描述。该实现利用了Boost Spirit作为PEG解析器生成器。我会像在这里一样生成输出,只不过我会在语法的语义动作内部进行。那个解决方案将比这里介绍的方案慢得多,但更加灵活,因为使用解析器生成器可以更轻松地适应模板语法的更复杂行为。 - sehe
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接