查找字符串中子字符串的计数

Posted

技术标签:

【中文标题】查找字符串中子字符串的计数【英文标题】:find the count of substring in string 【发布时间】:2012-02-21 13:48:27 【问题描述】:

我必须使用 C 语言。 我正在使用函数strstr,但它只找到第一次出现。

我对算法的想法类似于在字符串中搜索,而 strstr 不返回 null 并且 在每个循环上子串主字符串。 我的问题是如何做到这一点?

【问题讨论】:

【参考方案1】:

你可以这样做

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

   count++;
   tmp++;

也就是说,当你得到一个结果时,从字符串的下一个位置重新开始搜索。

strstr() 不仅可以从字符串的开头开始工作,而且可以从任何位置开始。

【讨论】:

如果它们需要是不同的子字符串,你可以考虑count+=strlen(string2find) 编辑,我添加了针对 string2find="" 的问题的保护 @Dave,小心“”的无限循环 @Dave 和未来的读者,我相信你的意思是tmp += strlen(string2find)。在您的示例中,您将按字符串的长度增加出现次数! 如果您在“zzzz”中找到“zz”,它将返回 3 并且(使用 tmp++)我相信这是正确的答案,如果您执行类似 tmp += strlen(string2find) 之类的操作,这将只是返回 2。【参考方案2】:

是否应该使用已处理的字符串部分?

例如,在foooo2 或3中搜索oo 的预期答案是什么?

如果是后者(我们允许子串重叠,答案是三个),那么 Joachim Isaksson suggested 是正确的代码。

如果我们搜索不同的子字符串(答案应该是两个),那么请看下面的代码(以及在线示例here):

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

Output

'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】:

假设ssubstr 非空且非空:

/* #times substr appears in s, no overlaps */
int nappear(const char *s, const char *substr)

    int n = 0;
    const char *p = s;

    size_t lenSubstr = strlen(substr);

    while (*p) 
        if (memcmp(p, substr, lenSubstr) == 0) 
            ++n;
            p += lenSubstr;
         else 
            ++p;
    
    return n;

【讨论】:

【参考方案6】:
/* 
 * 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);

【讨论】:

不要无缘无故使用全局变量。 void main 错误;应该是int main"%[^\n]s" 没有做你想做的事; s 不是 % 指令的一部分,需要输入文字 s。您没有指定输入的上限;这是潜在的缓冲区溢出。如果必须使用它,请始终检查 scanf 的返回值。不要使用scanf 进行用户输入。 strlen 返回 size_t,而不是 intwhile 条件中有多余的括号;虽然本身不​​是错误,但如果您将== 拼写为=,这会使gcc 给您的警告静音。 while 循环不检查字符串结尾,如果所有字符都匹配,则可以在strsub 的结尾处运行。 jcount 始终设置在一起;它们实际上是相同的变量。你的算法完全坏了:它没有找到例如"ab""aab". 一般来说,避免发布仅包含代码的答案。对算法的描述或对您的答案与其他答案有何不同的解释会有所帮助。

以上是关于查找字符串中子字符串的计数的主要内容,如果未能解决你的问题,请参考以下文章

Java中字符串中子串的查找共有四种方法(indexof())

查找字符串中子字符串最后一次出现的索引

如何获取 hive 中子字符串的计数

在字符串 C# 中查找子字符串的计数

查找数组中每个字符串的最小唯一子字符串

子字符串计数