Как найти все позиции подстроки в строке?

Как я могу это сделать? Я хочу найти большую строку для всех местоположений строки.

Ответ 1

Два других ответа верны, но они очень медленны и имеют сложность O (N ^ 2). Но существует алгоритм Knuth-Morris-Pratt, который находит все подстроки в сложности O (N).

изменить

Также есть еще один алгоритм, называемый так называемой "Z-функцией" с сложностью O (N), но я не мог найти английский источник этого алгоритма (возможно, потому, что есть еще одна более известная вещь с тем же именем - Z- функция Римана), поэтому просто поместите здесь свой код и объясните, что он делает.

void calc_z (string &s, vector<int> & z)
{
    int len = s.size();
    z.resize (len);

    int l = 0, r = 0;
    for (int i=1; i<len; ++i)
        if (z[i-l]+i <= r)
            z[i] = z[i-l];
        else
        {
            l = i;
            if (i > r) r = i;
            for (z[i] = r-i; r<len; ++r, ++z[i])
                if (s[r] != s[z[i]])
                    break;
            --r;
        }
}
int main()
{
    string main_string = "some string where we want to find substring or sub of string or just sub";
    string substring = "sub";
    string working_string = substring + main_string;
    vector<int> z;
    calc_z(working_string, z);

    //after this z[i] is maximal length of prefix of working_string
    //which is equal to string which starting from i-th position of
    //working_string. So the positions where z[i] >= substring.size()
    //are positions of substrings.

    for(int i = substring.size(); i < working_string.size(); ++i)
        if(z[i] >=substring.size())
            cout << i - substring.size() << endl; //to get position in main_string
}

Ответ 2

Использование std::string::find. Вы можете сделать что-то вроде:

std::string::size_type start_pos = 0;
while( std::string::npos != 
          ( start_pos = mystring.find( my_sub_string, start_pos ) ) )
{
    // do something with start_pos or store it in a container
    ++start_pos;
}

ИЗМЕНИТЬ: Doh! Спасибо за замечание, Наваз! Лучше?

Ответ 3

Я добавлю для полноты, есть еще один подход, который возможен с std::search, работает как std::string::find, разница в том, что вы работаете с итераторами, что-то вроде:

std::string::iterator it(str.begin()), end(str.end());
std::string::iterator s_it(search_str.begin()), s_end(search_str.end());

it = std::search(it, end, s_it, s_end);

while(it != end)
{
  // do something with this position..

  // a tiny optimisation could be to buffer the result of the std::distance - heyho..
  it = std::search(std::advance(it, std::distance(s_it, s_end)), end, s_it, s_end);
}

Я нахожу, что это иногда превосходит std::string::find, esp. если вы представляете свою строку как vector<char>.

Ответ 4

Просто use std::string::find(), который возвращает позицию, в которой была найдена подстрока, или std::string::npos, если ни один не найден.

Здесь - документация.

Вот пример, взятый из этой документации:

// string::find
#include <iostream>
#include <string>
using namespace std;

int main ()
{
  string str ("There are two needles in this haystack with needles.");
  string str2 ("needle");
  size_t found;

  // different member versions of find in the same order as above:
  found=str.find(str2);
  if (found!=string::npos)
    cout << "first 'needle' found at: " << int(found) << endl;

  found=str.find("needles are small",found+1,6);
  if (found!=string::npos)
    cout << "second 'needle' found at: " << int(found) << endl;

  found=str.find("haystack");
  if (found!=string::npos)
    cout << "'haystack' also found at: " << int(found) << endl;

  found=str.find('.');
  if (found!=string::npos)
    cout << "Period found at: " << int(found) << endl;

  // let replace the first needle:
  str.replace(str.find(str2),str2.length(),"preposition");
  cout << str << endl;

  return 0;
}