在C ++中用任意长度的字符串替换字符串

时间:2014-09-29 14:45:48

标签: c++ macos stdstring ostringstream

我有一个来自ostringstream的字符串。我目前正在尝试替换此字符串中的一些字符(content.replace(content.begin(), content.end(), "\n", "");),但有时我会遇到异常:

malloc: *** mach_vm_map(size=4294955008) failed (error code=3)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
std::bad_alloc

我怀疑这是因为字符串太大了。这些情况的最佳做法是什么?在堆上声明字符串?

更新

我的完整方法:

xml_node HTMLDocument::content() const {
  xml_node html = this->doc.first_child();
  xml_node body = html.child("body");
  xml_node section = body.child("section");
  std::ostringstream oss;
  if (section.type() != xml_node_type::node_null) {
    section.print(oss);
  } else {
    body.print(oss);
  }
  string content;
  content = oss.str();
  content.replace(content.begin(), content.end(), "<section />", "<section></section>");
  content.replace(content.begin(), content.end(), "\t", "");
  xml_node node;
  return node;
}

4 个答案:

答案 0 :(得分:1)

没有std::string::replace成员函数的重载接受一对迭代器,一个const char*要搜索,const char*用作替换,这就是你的问题所在从:

content.replace(content.begin(), content.end(), "\n", "");

匹配以下重载:

template <class InputIterator>
string& replace(iterator i1, iterator i2,
                InputIterator first, InputIterator last);

即,"\n"""被视为范围<first; last),这取决于他们拥有的地址,是否会导致程序崩溃。

您必须使用std::regex或实现您自己的迭代std::string的逻辑,并用替换字符串替换任何遇到的模式。

答案 1 :(得分:1)

行:

content.replace(content.begin(), content.end(), "<section />", "<section></section>");
content.replace(content.begin(), content.end(), "\t", "");

导致未定义的行为。它们匹配功能:

template<class InputIterator>
std::string& std::string::replace(
    const_iterator i1, const_iterator i2,
    InputIterator j1, InputIterator j2);

InputIterator解析为char const*。问题是 两个迭代器之间的距离,以及是否 第二个可以从第一个到达,是未定义的,因为它们 指向完全不相关的内存。

从你的代码中,我认为你不明白什么 std::string::replace。它取代了[i1,i2)中的范围 包含由范围[j1,j2)定义的文本的字符串。它 进行任何搜索和比较;它是在之后使用 你找到了需要更换的范围。主叫:

content.replace(content.begin(), content.end(), "<section />", "<section></section>");

具有与以下完全相同的效果:

content = std::string( "<section />", "<section></section>");

,肯定你想要的东西。

在C ++ 11中,有一个regex_replace函数可能是 一些用途,虽然如果你真的这么做非常大 字符串,它可能不是最高性能(添加 正则表达式的灵活性是有代价的); ID 可能使用类似的东西:

std::string
searchAndReplace(
    std::string const& original,
    std::string const& from,
    std::string const& to)
{
    std::string results;
    std::string::const_iterator current = original.begin();
    std::string::const_iterator end = original.end();
    std::string::const_iterator next = std::search( current, end, from.begin(), from.end() );
    while ( next != end ) {
        results.append( current, next );
        results.append( to );
        current = next + from.size();
        next = std::search( current, end, from.begin(), from.end() );
    }
    results.append( current, next );
    return results;
}

对于非常大的字符串,一些用于猜测大小的启发式, 然后在reserve上执行results可能是一个好主意 同样。

最后,由于你的第二行只删除'\t',你就是了 最好使用std::remove

content.erase( std::remove( content.begin(), content.end(), '\t' ), content.end() );

答案 2 :(得分:0)

AFAIK stl字符串总是在堆上分配,如果它们超过某个(小)大小,例如32 chars in Visual Studio

如果获得分配例外,您可以做什么:

  • 使用自定义分配器
  • 使用&#34; rope&#34;类。

错误的分配可能并不意味着你的内存不足,更有可能是你的连续内存不足。绳索类可能更适合您,因为它在内部分配了字符串。

答案 3 :(得分:0)

这是从字符串中删除字符的正确(且合理有效)方法之一,如果您想要复制并保留原始字符:

#include <algorithm>
#include <string>

std::string delete_char(std::string src, char to_remove)
{
    // note: src is a copy so we can mutate it

    // move all offending characters to the end and get the iterator to last good char + 1
    auto begin_junk = std::remove_if(src.begin(),
                                     src.end(),
                                     [&to_remove](const char c) { return c == to_remove; });
    // chop off all the characters we wanted to remove
    src.erase(begin_junk,
              src.end());

    // move the string back to the caller's result
    return std::move(src);
}

这样叫:

std::string src("a\nb\bc");
auto dest = delete_char(src, '\n');
assert(dest == "abc");

如果您希望修改字符串,则只需:

src.erase(std::remove_if(src.begin(), src.end(), [](char c) { return c == '\n'; }), src.end());