给定以下字符串,"Hi ~+ and ^*. Is ^* still flying around ~+?"
我想用“Bobby”和“Danny”替换所有出现的"~+"
and "^*"
,所以字符串变成:
"Hi Bobby and Danny. Is Danny still flying around Bobby?"
我宁愿不必调用 Boost 替换函数两次来替换两个不同值的出现。
给定以下字符串,"Hi ~+ and ^*. Is ^* still flying around ~+?"
我想用“Bobby”和“Danny”替换所有出现的"~+"
and "^*"
,所以字符串变成:
"Hi Bobby and Danny. Is Danny still flying around Bobby?"
我宁愿不必调用 Boost 替换函数两次来替换两个不同值的出现。
我设法使用 Boost.Iostreams 实现了所需的替换功能。具体来说,我使用的方法是使用正则表达式来匹配要替换的内容的过滤流。我不确定千兆字节大小的文件的性能。当然,您需要对其进行测试。无论如何,这是代码:
#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
需要将整个字符序列读入内存,这对于千兆字节大小的输入来说毫无用处。那好吧...
我确实注意到它已经一年了,因为它是活跃的,但它是值得的。我今天在 CodeProject 上看到一篇声称可以解决这个问题的文章——也许你可以从那里借鉴一些想法:
我不能保证它的正确性,但可能值得一看。:)
该实现肯定需要将整个字符串保存在内存中,但是您可以轻松地解决这个问题(与执行替换的任何其他实现一样)只要您可以将输入拆分为块并保证您永远不会在在要替换的符号内。(在您的情况下,一种简单的方法是在下一个字符不是符号中使用的任何字符的位置拆分。)
--
除了性能之外还有一个原因(尽管这在我的书中是一个充分的理由)将“ReplaceMultiple”方法添加到一个字符串库中:简单地执行 N 次替换操作通常是不正确的。
如果替换符号的值不受约束,则值最终会在后续替换操作中被视为符号。(在某些情况下您可能确实想要这个,但在某些情况下您肯定不需要。使用看起来很奇怪的符号会降低问题的严重性,但不能解决问题,而且“丑陋”是因为要格式化的字符串可能是用户可定义的 - 因此不需要外来字符。)
但是,我怀疑我不能轻易找到通用的多替换实现是有充分理由的。“ReplaceMultiple”操作通常(显然)没有明确定义。
要了解这一点,请考虑“将 'aa' 替换为 '!'可能意味着什么。'咩'和'?' 在字符串“abaa”中?结果是'ab!' 或“一个?” - 或者这样的替换是非法的?
可以要求符号“无前缀”,但在许多情况下这是不可接受的。假设我想用它来格式化一些模板文本。并说我的模板是用于代码的。我想用仅在运行时知道的数据库表名替换“§table”。如果我现在不能在同一个模板中使用“§t”,那会很烦人。模板化的脚本可能是完全通用的东西,而且你瞧,有一天我遇到的客户实际上在他的表名中使用了“§”……这可能会使我的模板库变得不那么有用。
也许更好的解决方案是使用递归下降解析器,而不是简单地替换文字。:)
Boost string_algo 确实有一个 replace_all 功能。你可以用那个。
我建议使用 std::map。所以你有一组替换,所以这样做:
std::map<std::string,std::string> replace;
replace["~+"]=Bobby;
replace["^*"]=Danny;
然后您可以将字符串放入字符串向量中并检查每个字符串是否出现在地图中,如果确实替换了它,您还需要从末尾删除任何标点符号。或者将它们添加到替换中。然后,您可以在一个循环中完成。我不确定这是否真的比 boost 更有效或更有用。
我建议使用 Boost Format 库。而不是~+
and^*
你然后使用%1%
and%2%
等等,更系统一点。
文档中的示例:
cout << boost::format("writing %1%, x=%2% : %3%-th try") % "toto" % 40.23 % 50;
// prints "writing toto, x=40.230 : 50-th try"
干杯&hth.,
– 阿尔夫