如何找到一个字符串是否位于另一个字符串内并替换它?

时间:2017-04-11 18:10:24

标签: c++ substr

我需要以下程序的帮助。我不知道如何检查string2内是否出现string1,然后将其替换为string3

  

编写名为replaceSubstring的函数。该函数应该接受三个字符串对象参数。我们称他们为string1, string2, and string3。它应该string1搜索string2的所有匹配项。如果发现string2,则应将其替换为string3。使用完整的程序演示和测试该功能。

     

例如,假设这三个参数具有以下值:

     

string1:“狗跳过篱笆”

     

string2:“the”

     

string3:“那个”

     

使用这三个参数,该函数将返回一个字符串对象,其值为“狗跳过该栅栏”。在完整的程序中演示该功能。

int main()
{
    string string1 = "xyzxyzxyz";
    string string2 = "xyz";
    string string3 = "a";
    replaceSubstring(string1, string2, string3);
    return 0;
}

void replaceSubstring(string string1, string string2, string string3)
{
    string result;
    for (int i = 0; i < string1.length(); i++){
        if (string1.find(string2, i)){
            result = string1.replace(i, string3.length()+i, string3);
        }
    }
    cout << result;

}

4 个答案:

答案 0 :(得分:1)

快速执行此操作的方法是使用提升字符串算法库[{3}}

#include <boost/algorithm/string/replace.hpp>
{ // 1. 
  string test = "abc def abc def";
  boost::replace_all(test, "abc", "hij");
  boost::replace_all(test, "def", "klm");
}


{ // 2.
  string test = boost::replace_all_copy
  (  boost::replace_all_copy<string>("abc def abc def", "abc", "hij")
  ,  "def"
  ,  "klm"
  );
}

因为,如here所述:

  

C ++中没有一个内置函数可以做到这一点。如果您想将一个子字符串的所有实例替换为另一个子字符串,可以通过混合调用string :: find和string :: replace来实现。例如:       size_t index = 0;       while(true){            / *找到要替换的子字符串。 * /            index = str.find(&#34; abc&#34;,index);            if(index == std :: string :: npos)break;

     /* Make the replacement. */
     str.replace(index, 3, "def");

     /* Advance index forward so the next iteration doesn't pick it up as well. */
     index += 3;
}

如果目标是实现您自己的代码来替换匹配的字符串,我建议您阅读hereZ算法。对于快速且肮脏的解决方案,请参阅下面的KMP

// C program for Naive Pattern Searching algorithm
#include<stdio.h>
#include<string.h>

void search(char *pat, char *txt)
{
    int M = strlen(pat);
    int N = strlen(txt);

    /* A loop to slide pat[] one by one */
    for (int i = 0; i <= N - M; i++)
    {
        int j;

        /* For current index i, check for pattern match */
        for (j = 0; j < M; j++)
            if (txt[i+j] != pat[j])
                break;

        if (j == M)  // if pat[0...M-1] = txt[i, i+1, ...i+M-1]
           printf("Pattern found at index %d \n", i);
    }
}

/* Driver program to test above function */
int main()
{
   char txt[] = "AABAACAADAABAAABAA";
   char pat[] = "AABA";
   search(pat, txt);
   return 0;
}

找到位置后,编写一个方法来构建一个新字符串,并从这些位置开始逐个替换,添加,删除字符。

答案 1 :(得分:0)

string.find返回找到的字符串的第一个字符的索引。这是一个小例子。

int main()
    {
    string myString = "ThisMessageIsPointLess";

    string strToFind = "Is";
    size_t idx = myString.find(strToFind.c_str());
    // idx = 11 because 'Is' starts at the 11th position in the string

    idx = myString.find("Foo");
    // idx == std::string::npos because it hasn't found "Foo" in myString

在所有情况下,您应该检查是否在字符串中找到了子字符串。您只需要将返回的索引与库中的默认失败值进行比较:

    if (idx == std::string::npos)
        {
        // Failed to find the substring
        return false;
        }

现在,std::string::replace有很多重载,他们可以做不同的事情。我建议你使用带有两个迭代器和'替换'字符串的那个。

    string replacement = "Seems";
    myString.replace(myString.begin() + idx, myString.begin() + idx + strToFind.size(), replacement.c_str());
    // myString = "ThisMessageSeemsPointless"
    return true;

我们使用的重载需要替换第一个字符的迭代器,要替换的最后一个字符的迭代器和替换字符串。我们知道字符串从头开始于idx。通过简单的逻辑,我们知道它应该从idx + strToFind.size()开始结束。

PS:为变量命名可能是相关的,以便其他人更容易理解它们。不要在名称中加上“字符串”;它的类型是string,所以这是多余的。考虑将string2替换为token,将string3替换为newTokenreplacement ......任何比数字更有意义的内容。

最后,您可能希望通过引用(对于string1)和const-reference(对于string2和string3)传递变量。这样可以避免创建字符串的本地副本,并且可以提高整体性能。

bool replaceSubstring(string& string1, string const& string2, string const& string3)

答案 2 :(得分:0)

如果没有像boost这样的额外库,您需要使用std库编写自定义替换算法。这个将计算结果字符串作为返回值。

string replaceSubstring(const string& string1, const string& string2, const string& string3)
{
    string result;
    size_t posStart = 0, posFound;
    for(; (posFound = string1.find(string2, posStart)) != string1.npos;
           posStart = posFound + string2.size())
    {
        copy(string1.begin()+posStart, string1.begin()+posFound, back_inserter(result));
        result.append(string3);
    }
    copy(string1.begin()+posStart, string1.end(), back_inserter(result));
    return result;
}

当然,您可以通过将fisrt参数从void更改为const string& string1并在返回之前从结果中指定它,轻松将其更改为string& string1

如果这个代码是在大字符串上运行的,并且如果事实证明后面插入所需的分配没有被实现正确优化(@RemyLebeau在评论中提出了一个问题),你可以做一些<在copy陈述之前的预订

...
result.reserve(result.size() + posFound + string3.size() + 2 - posStart);
copy(string1.begin()+posStart, string1.begin() + posFound, back_inserter(result));

...
result.reserve(result.size() + string1.size() + 2 - posStart);
copy(string1.begin()+posStart, string1.end(), back_inserter(result));

答案 3 :(得分:0)

你的功能有几个问题:

  1. 你没有按照说明操作! “该函数将返回一个字符串对象 ... ”。你的功能不会返回任何东西。它只是将结果输出到控制台屏幕。那应该是main()的责任。

  2. 您有正确的想法使用std::string::find()std::replace(),但您完全错误地使用它们。

    • find()返回子字符串的索引,如果未找到,则返回-1(技术上为std::string::npos)。除0之外的任何值都将在if表达式中评估为true。您的代码假设子字符串在您作为输入参数传递到find()的索引处找到,并且根本无法保证。

    • 您正在调用的replace()版本需要一个起始索引和要替换的字符数。您没有将find()返回的索引传递给它,并且您也传递了错误的字符数。

    • 您也是一次循环输入字符串一个字符。在你循环的同一个输入字符串中替换子字符串将会对你的循环逻辑造成严重破坏。

  3. 话虽如此,试试这个:

    string replaceSubstring(const string &string1, const string &string2, const string &string3)
    {
        string result = string1;
        string::size_type pos = 0;
        do
        {
            pos = result.find(string2, pos);
            if (pos == string::npos) break;
            result.replace(pos, string2.length(), string3);
            pos += string3.length();
        }
        while (true);
        return result;
    }
    
    int main()
    {
        string string1 = "the dog jumped over the fence";
        string string2 = "the";
        string string3 = "that";
        string result = replaceSubstring(string1, string2, string3);
        cout << result;
        return 0;
    }