3

我想在不使用外部库的情况下替换一些单词。我的第一次尝试是复制字符串,但效率不高,所以这是我使用地址的另一次尝试:

void ReplaceString(std::string &subject, const std::string &search, const std::string &replace) 
{
    size_t position = 0;
    while ((position = subject.find(search, position)) != std::string::npos)    //if something messes up --> failure
    {
         subject.replace(position, search.length(), replace);
         position = position + replace.length();
    }
}

因为这也不是很有效,我想用另一个东西,但我卡住了;我想使用一个函数,比如replace_stuff(std::string & a);使用string.replace()string.find()(用 for 循环或其他东西解析它),然后使用std::map <std::string,std::string>;它对我来说非常方便。

我想将它用于大量输入单词。(假设用一些无害的词代替许多坏词)

4

4 回答 4

2

您的问题的问题是标准库中缺少必要的组件。如果你想要一个高效的实现,你可能需要一个trie来进行高效的查找。写一个作为答案的一部分将是很多代码的方式。

如果您使用 astd::map或者,如果您的环境中可以使用 C++11 std::unordered_map,则您将需要利用有关输入字符串和映射中的搜索替换对的附加信息。然后,您将对字符串进行标记并检查每个标记是否需要替换。使用指向输入字符串的位置是一个好主意,因为它可以避免复制数据。这使我们:

效率将取决于内存访问(读取和写入),因此您不应修改输入字符串。通过从空字符串开始并附加输入中的片段来创建输出。检查输入的每个部分:如果是一个单词,检查它是否需要替换或者是否未修改地附加到输出中。如果它不是单词的一部分,则不加修改地附加它。

于 2013-03-30T06:50:15.593 回答
2

听起来您想用无害的单词替换字符串中的所有“坏”词,但您当前的实现效率低下,因为坏词列表远大于输入字符串的长度 ( subject)。它是否正确?

如果是这样,下面的代码应该会提高效率。如您所见,我必须将映射作为参数传递,但如果您的函数将成为类的一部分,则无需这样做。

void ReplaceString(std::string &subject, const std::map<std::string, std::string>& replace_map) 
{
    size_t startofword = 0, endofword = 0;
    while(startofword < subject.size())
    {
      size_t length = std::string::npos;

      //get next word in string
      endofword = subject.find_first_of(" ", startofword);
      if(endofword != std::string::npos)
        length = endofword-startofword;

      std::string search = subject.substr(startofword, length);

      //try to find this word in the map
      if(replace_map.find(search) != replace_map.end())
      {
        //if found, replace the word with a new word
        subject.replace(startofword, length, replace_map[search]);
        startofword += replace_map[search].length();
      }
      else
      {
        startofword += length;
      }

    }

}
于 2013-03-30T06:53:51.643 回答
2

我使用以下功能,希望对您有所帮助:

//=============================================================================
//replaces each occurence of the phrase in sWhat with sReplacement
std::string& sReplaceAll(std::string& sS, const std::string& sWhat, const std::string& sReplacement)
{
    size_t pos = 0, fpos;
    while ((fpos = sS.find(sWhat, pos)) != std::string::npos)
    {
        sS.replace(fpos, sWhat.size(), sReplacement);
        pos = fpos + sReplacement.length();
    }
    return sS;
}

//=============================================================================
// replaces each single char from sCharList that is found within sS with entire sReplacement
std::string& sReplaceChars(std::string& sS, const std::string& sCharList, const std::string& sReplacement)
{
    size_t pos=0;
    while (pos < sS.length())
    {
        if (sCharList.find(sS.at(pos),0)!=std::string::npos) //pos is where a charlist-char was found
        {
            sS.replace(pos, 1, sReplacement);
            pos += sReplacement.length()-1;
        }
        pos++;  
    }
    return sS;
}
于 2013-03-30T07:06:21.333 回答
0

你可以创建一个类,比如 Replacer:

class Replacer 
{
  std::map<std::string,> replacement;

public:
  Replacer()
  {
     // init the map here
     replacement.insert ( std::pair<std::string,std::string>("C#","C++") );
     //...
  }
  void replace_stuff(std::string & a);
}

然后 replace_stuff 定义将与您的原始 ReplaceString 非常相似(它将使用映射条目而不是传递的参数)。

于 2013-03-30T14:48:26.643 回答