Найти счетчик подстроки в строке

Мне нужно найти счетчик подстроки в строке с использованием языка C. Я использую функцию strstr, но она находит только первое вхождение.

Мое представление об алгоритме - это что-то вроде поиска в строке, а strstr не возвращает null и подстроить основную строку в каждом цикле. Мой вопрос: как это сделать?

Ответ 1

Вы можете сделать что-то вроде

int count = 0;
const char *tmp = myString;
while(tmp = strstr(tmp, string2find))
{
   count++;
   tmp++;
}

То есть, когда вы получите результат, снова начните поиск в следующей позиции строки.

strstr() работает не только с начала строки, но и с любой позиции.

Ответ 2

Должны ли уже обработанные части строки использоваться или нет?

Например, каков foooo ответ для случая поиска oo в foooo, 2 или 3?

  • Если последнее (мы допускаем перекрытие подстрок, а ответ равен трем), то Иоахим Исакссон предложил правильный код.

  • Если мы ищем разные подстроки (ответ должен быть два), то посмотрите код ниже (и онлайн-пример здесь):

    char *str = "This is a simple string";
    char *what = "is";
    
    int what_len = strlen(what);
    int count = 0;
    
    char *where = str;
    
    if (what_len) 
        while ((where = strstr(where, what))) {
            where += what_len;
            count++;
        }
    

Ответ 3

ИСПОЛЬЗУЙТЕ KMP, и вы можете сделать это за O (n)

int fail[LEN+1];
char s[LEN];
void getfail()
{
    //f[i+1]= max({j|s[i-j+1,i]=s[0,j-1],j!=i+1})
    //the correctness can be proved by induction
    for(int i=0,j=fail[0]=-1;s[i];i++)
    {
        while(j>=0&&s[j]!=s[i]) j=fail[j];
        fail[i+1]=++j;
        if (s[i+1]==s[fail[i+1]]) fail[i+1]=fail[fail[i+1]];//optimizing fail[]
    }
}

int kmp(char *t)// String s is pattern and String t is text!
{
    int cnt=0;
    for(int i=0,j=0;t.s[i];i++)
    {
        while(j>=0&&t.s[i]!=s[j]) j=fail[j];
        if (!s[++j])
        {
            j=fail[j];
            cnt++;
        }
    }
    return cnt;// how many times s appeared in t.
}

Ответ 4

Результаты могут отличаться в зависимости от того, разрешаете ли вы перекрытие или нет:

// gcc -std=c99
#include <stdbool.h>
#include <stdio.h>
#include <string.h>

static int
count_substr(const char *str, const char* substr, bool overlap) {
  if (strlen(substr) == 0) return -1; // forbid empty substr

  int count = 0;
  int increment = overlap ? 1 : strlen(substr);
  for (char* s = (char*)str; (s = strstr(s, substr)); s += increment)
    ++count;
  return count;
}

int main() {
  char *substrs[] = {"a", "aa", "aaa", "b", "", NULL };
  for (char** s = substrs; *s != NULL; ++s)
    printf("'%s' ->  %d, no overlap: %d\n", *s, count_substr("aaaaa", *s, true),
       count_substr("aaaaa", *s, false));
}

Выход

'a' ->  5, no overlap: 5
'aa' ->  4, no overlap: 2
'aaa' ->  3, no overlap: 1
'b' ->  0, no overlap: 0
'' ->  -1, no overlap: -1

Ответ 5

/* 
 * C Program To Count the Occurence of a Substring in String 
 */
#include <stdio.h>
#include <string.h>

char str[100], sub[100];
int count = 0, count1 = 0;

void main()
{
    int i, j, l, l1, l2;

    printf("\nEnter a string : ");
    scanf("%[^\n]s", str);

    l1 = strlen(str);

    printf("\nEnter a substring : ");
    scanf(" %[^\n]s", sub);

    l2 = strlen(sub);

    for (i = 0; i < l1;)
    {
        j = 0;
        count = 0;
        while ((str[i] == sub[j]))
        {
            count++;
            i++;
            j++;
        }
        if (count == l2)
        {
            count1++;                                   
            count = 0;
        }
        else
            i++;
    }    
    printf("%s occurs %d times in %s", sub, count1, str);
}