如何查找字符串中子字符串的所有出现次数和所有位置?

时间:2017-06-18 20:09:29

标签: c string char substring

我需要查找所有出现并输出字符串中子字符串的所有位置。

例如:我的字符串是abaaab,我的子字符串是aa,位置是34,因为在aaa我的substr重复了两次

我希望最后的位置从右到左打印,在子字符串的位置后我想要我的子串的出现次数。

我试着去做,我有这个:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(){
    char *str, c;
    int x = 0, y = 1;

    str = (char*)malloc(sizeof(char));

    printf("Inserisci stringa principale : ");

        while (c != '\n') {
        // read the input from keyboard standard input
        c = getc(stdin);

        // re-allocate (resize) memory for character read to be stored
        str = (char*)realloc(str, y * sizeof(char));

        // store read character by making pointer point to c
        str[x] = c;

        x++;
        y++;
        }

    str[x] = '\0'; // at the end append null character to mark end of string

    printf("\nLa stringa inserita : %s", str);

      char *sub, b;
      int w = 0, z = 1;

      sub = (char*)malloc(sizeof(char));

      printf("Immetti sottostringa da cercare : ");

          while (b != '\n') {
            // read the input from keyboard standard input
            b = getc(stdin);

            // re-allocate (resize) memory for character read to be stored
            sub = (char*)realloc(sub, z * sizeof(char));

            // store read character by making pointer point to c
            sub[w] = b;

            w++;
            z++;
          }

      sub[w] = '\0'; // at the end append null character to mark end of string

    char *p1, *p2, *p3;
    int i=0,j=0,flag=0;

      p1 = str;
      p2 = sub;

      for(i = 0; i<strlen(str); i++)
      {
        if(*p1 == *p2)
          {
              p3 = p1;
              for(j = 0;j<strlen(sub);j++)
              {
                if(*p3 == *p2)
                {
                  p3++;p2++;
                } 
                else
                  break;
              }
              p2 = sub;
              if(j == strlen(sub))
              {
                 flag = 1;
                printf("\nSottostringa trovata all'indice : %d\n",i);
              }
          }
        p1++; 
      }
      if(flag==0)
      {
           printf("Sottostringa non trovata");
      }
    free(str);
    free(sub);
    return (0);
    }

但它只显示第一次出现的位置,而不是出现次数。

3 个答案:

答案 0 :(得分:2)

您的代码中存在多个问题:

  • 您的字符串重新分配方案不正确:分配的空间对于字符串来说太短了一个字节,您永远不会测试内存分配失败。如果您的系统支持getline(),或者至少编写一个函数来分解代码,您可以使用c

  • 第一次循环测试c != '\n'时,
  • #include <stdio.h> #include <stdlib.h> #include <string.h> /* read an allocated string from stream. stop at newline, not included in string. Return NULL upon EOF */ char *my_getline(FILE *stream) { char *line = NULL; size_t pos = 0; int c; while ((c = getc(stream)) != EOF) { char *newp = realloc(line, pos + 2); if (newp == NULL) { free(line); return NULL; } line = newp; if (c == '\n') break; line[pos++] = (char)c; } if (line) { line[pos] = '\0'; } return line; } int main(void) { char *str, *sub; size_t len1, len2, i, count = 0; // type the main string printf("Inserisci stringa principale :\n"); str = my_getline(stdin); // type the substring to search for printf("Immetti sottostringa da cercare :\n"); sub = my_getline(stdin); if (str && sub) { len1 = strlen(str); len2 = strlen(sub); for (i = 0; i + len2 <= len1; i++) { if (!memcmp(str + i, sub, len2)) { count++; // substring found at offset printf("Sottostringa trovata all'indice : %zu\n", i); } } if (count == 0) { // substring not found printf("Sottostringa non trovata\n"); } } free(str); free(sub); return 0; } 未初始化:这有未定义的行为。

  • 您的匹配算法过于复杂:您同时使用索引值和移动指针。使用其中一种。

这是一个简化版本:

strstr()

注意:

  • 上面的代码在搜索字符串中的每个偏移处找到空子字符串的匹配项。是否应该找到匹配是一个规范问题,但这种行为与strstr()的行为一致。

  • 您还可以使用标准函数strstr()来查找匹配项。

以下是使用if (str && sub) { for (char *p = str; (p = strstr(p, sub)) != NULL; p++) { count++; // substring found at offset printf("Sottostringa trovata all'indice : %tu\n", p - str); if (*p == '\0') /* special case for the empty string */ break; } if (count == 0) { // substring not found printf("Sottostringa non trovata\n"); } } 的主循环版本:

assert_no_difference 'User.count' do
  post users_path, params: { user: { name:  "",
                                     email: "user@invalid",
                                     password:              "foo",
                                     password_confirmation: "bar" } }
end

答案 1 :(得分:1)

我检查了你的代码,似乎你的代码在行中有问题

if(j == strlen(sub))

由于j从0开始,它总是比子字符串的长度小1,将代码更改为

if(j+1 == strlen(sub))

它应该可以解决你的问题。

对于出现次数,只要与子字符串匹配,就需要计算另一个变量,修改if块

if(j+1 == strlen(sub))
{
      flag = 1;
      occurrences+=1;  //declare variable occurrences and initialize it to 0
      printf("\nSottostringa trovata all'indice : %d\n",i);
}

然后在循环结束后,只需打印'occurrence'以获得所需的结果。

这也不是解决问题的有效方法,您可以参考

https://www.topcoder.com/community/data-science/data-science-tutorials/introduction-to-string-searching-algorithms/

更好的方法。

答案 2 :(得分:0)

查找每个事件的一种简单方法是在循环中调用strstr。每次比赛结束后,让strstr搜索找到匹配项后的一个位置:

int main( ) {

    const char *string = "abaaab";
    const char *toSearch = "aa";
    int nrOfOccurences = 0;
    printf("searching for occurences of '%s' in string '%s':\n", string, toSearch);
    const char* pos = string;
    while (pos) {
        pos = strstr(pos, toSearch);
        if (pos) {
            printf("found occurence at position %td\n", pos-string);
            nrOfOccurences++;
            pos++;  // skip one character
        }
    }
    nrOfOccurences = findRecursive(string, toSearch, 0,0);
    printf("nr of occurences: %d\n", nrOfOccurences);
    return 0;
}

如果你需要 - 以某种方式说明 - 从最后一个开始打印出现的事件,你可以使用如下的递归函数。上面代码中的注释显示了如何使用它:

int findRecursive(const char* str, const char* toSearch, ptrdiff_t pos, int nrOfOccurences) {

    char *next = strstr(str, toSearch);
    if (next) {
        ptrdiff_t foundPos = pos + next - str;
        nrOfOccurences = findRecursive(next+1, toSearch, foundPos+1, nrOfOccurences+1);
        printf("occurence found at position %td\n", foundPos);
    }
    return nrOfOccurences;
}