簡體   English   中英

C ++中任意長度的字符串上的字符串替換

[英]String replacement in C++ on string of arbitrary length

我有一個從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;
}

沒有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) <first; last) ,這取決於它們具有的地址,是否會使程序崩潰。

您必須使用std::regex或實現自己的邏輯,該邏輯遍歷std::string並用替換std::string替換所有遇到的模式。

這些行:

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函數可能有用,盡管如果您確實在非常大的字符串上執行此操作,則它可能並不是最有效的(正則表達式的靈活性增加了代價); 我可能會使用類似:

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;
}

對於非常大的字符串,還可以使用一些試探法來猜測大小,然后對results進行reserve ,這也是一個好主意。

最后,由於第二行只是刪除了'\\t' ,因此最好使用std::remove

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

如果AFAIK stl字符串超過某個(較小)大小(例如, 在Visual Studio中為32個字符 ),則始終在堆上分配它們

如果遇到分配異常,該怎么辦:

  • 使用自定義分配器
  • 使用“ 繩索 ”類。

錯誤的分配可能並不意味着您已用完內存,更可能是連續內存已用完。 繩索類可能會更適合您,因為它會在內部逐段分配字符串。

如果要進行復制並保持原樣不變,這是從字符串中刪除字符的正確(且相當有效)的方法之一:

#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());

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM