C ++在一次传递中替换字符串中的多个字符串

时间:2010-10-08 23:42:45

标签: c++ string boost str-replace

给出以下字符串"Hi ~+ and ^*. Is ^* still flying around ~+?"

我想将所有出现的"~+""^*"替换为“Bobby”和“Danny”,因此字符串变为:

"Hi Bobby and Danny. Is Danny still flying around Bobby?"

我宁愿不必两次调用Boost替换函数来替换两个不同值的出现。

5 个答案:

答案 0 :(得分:7)

我设法使用Boost.Iostreams实现了所需的替换功能。具体来说,我使用的方法是使用正则表达式匹配要替换的过滤流。我不确定gigabyte文件的性能。你当然需要测试它。无论如何,这是代码:

#include <boost/regex.hpp>
#include <boost/iostreams/filter/regex.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <iostream>

int main()
{
   using namespace boost::iostreams;

   regex_filter filter1(boost::regex("~\\+"), "Bobby");
   regex_filter filter2(boost::regex("\\^\\*"), "Danny");

   filtering_ostream out;
   out.push(filter1);
   out.push(filter2);
   out.push(std::cout);

   out << "Hi ~+ and ^*. Is ^* still flying around ~+?" << std::endl;

   // for file conversion, use this line instead:
   //out << std::cin.rdbuf();
}

以上打印"Hi Bobby and Danny. Is Danny still flying around Bobby?"在运行时,就像预期一样。

如果你决定测量它,那么看到性能结果会很有趣。

丹尼尔

编辑:我刚刚意识到regex_filter需要将整个字符序列读入内存,这对于千兆字节大小的输入来说非常无用。哦,好吧......

答案 1 :(得分:3)

我注意到它已经过了一年,因为它是活跃的,但它的价值。 I came across an article on CodeProject今天声称要解决这个问题 - 也许你可以使用那里的想法:

我无法保证其正确性,但可能值得一看。 :)

实现肯定需要将整个字符串保存在内存中,但只要您可以将输入拆分为块并保证永远不会拆分,就可以轻松解决该问题(与执行替换的任何其他实现一样)。 里面的位置要替换的符号。 (在您的情况下,一种简单的方法是在下一个字符不是符号中使用的任何字符的位置拆分。)

-

有一个超出性能的原因(尽管这是我书中的充分理由)将“ReplaceMultiple”方法添加到一个字符串库中:简单地执行N次替换操作通常是不正确的。

如果替代符号的值不受约束,则最终可能会在后续替换操作中被视为符号。 (在某些情况下你实际上想要这个,但肯定有些情况你不这样做。使用看起来很奇怪的符号可以降低问题的严重性,但是不能解决问题,并且“很丑”,因为要格式化的字符串可能是用户可定义的 - 所以不应该需要外来字符。)

但是,我怀疑有一个很好的理由为什么我不能轻易找到一般的多替换实现。 “ReplaceMultiple”操作通常不会(显然)定义明确。

要看到这一点,请考虑将表示用“!”替换“aa”。 'baa'和'?'在字符串'abaa'中?结果是'ab!'还是'一个?' - 或者这样的替代非法?

人们可能要求符号“无前缀”,但在许多情况下这是不可接受的。假设我想用它来格式化一些模板文本。并说我的模板是代码。我想用仅在运行时知道的数据库表名替换“§table”。如果我现在不能在同一个模板中使用“§t”,那会很烦人。模板化的脚本可能是完全通用的,而且有一天,我遇到的客户实际上在他的表名中使用了“§”......可能使我的模板库变得不那么有用了。

一个更好的解决方案是使用递归下降解析器而不是简单地替换文字。 :)

答案 2 :(得分:0)

Boost string_algo确实有一个replace_all函数。你可以使用它。

答案 3 :(得分:0)

我建议使用Boost格式库。而不是~+^*,您可以使用%1%%2%等等,更系统一些。

文档示例:

cout << boost::format("writing %1%,  x=%2% : %3%-th try") % "toto" % 40.23 % 50; 
     // prints "writing toto,  x=40.230 : 50-th try"

干杯&amp;第h。,

- Alf

答案 4 :(得分:0)

我建议使用std :: map。所以你有一组替代品,所以:

std::map<std::string,std::string> replace;
replace["~+"]=Bobby;
replace["^*"]=Danny;

然后你可以将字符串放入字符串向量中并检查每个字符串是否出现在地图中,如果它确实替换了它,你还需要从结尾处取下任何标点符号。或者将这些添加到替换中。然后你可以在一个循环中完成它。我不确定这是否比提升更有效或更有用。