在C语言中多次使用strstr()函数来匹配同一字符串

4

我正在尝试编写一段代码,使用strstr提取在<body>和</body>标签之间的所有单词/字符串。但似乎它只能提取到第一个字符串"quick",然后就停止了。如何让代码在提取第一个字符串后继续提取接下来的字符串?

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

int main()
{

    char feed[] = "The <item> quick </item> brown <item> fox </item> jumps <item> over </item> the <item> lazy dog </item>";


    const char needle[] = "<item>";
    const char popo[] = "</item>";
    char *ret;
    char *ter;
    int n;
    n = 0;

    while (feed[n] != '\0')
    {
        ret = strstr(feed, needle)+6;
        ter = strstr(ret, popo);
        size_t len = ter - ret;
        char *res = (char*)malloc(sizeof(char)*(len+1));
        strncpy(res, ret, len);
        res[len] = '\0';

        printf("%s",res);
        n++;
    }
    return 0;
}

频繁使用回车键,减少空格键的使用,缩进代码! - Ed Heal
不要强制转换 malloc()ret = strstr(feed, needle)+6; 这个操作很危险,如果 strstr() 返回 NULL,你最终会得到 (void *)0x06 而不是 (void *)0x00,解引用这个地址会出问题。此外,使用 memcpy() 替代 strncpy(),像这样 memcpy(res, ret, len),在执行之前检查 res != NULL - Iharob Al Asimi
如果我去掉+6,输出将包括字符串"<item>"。 - Syvil San Pablo
在检查ret ! = NULL后,您可以添加<item>的长度,请参考我的答案。 - Iharob Al Asimi
2个回答

2

您需要使指针ret指向字符串的当前位置,并在每次迭代中将其增加长度,并将ret传递给第一个strstr()而不是feed,请查看此实现。

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

int main()
{

    char       feed[]   = "The <item> quick </item> brown <item> fox </item> "
                          "jumps <item> over </item> the <item> lazy dog </item>";
    const char needle[] = "<item>";
    const char popo[]   = "</item>";
    char      *head;
    int n;
    n = 0;

    head = feed;
    while (feed[n] != '\0')
    {
        char  *tail;
        char  *copy;
        size_t length;

        head = strstr(head, needle);
        /*            ^ always start at the current position. */
        if (head == NULL)
         {
            fprintf(stderr, "Invalid input...???\n");
            return -1;
         }
        tail   = strstr(head, popo);
        length = tail - head - 6;
        head  += 6;
        if (length < 0)
         {
            fprintf(stderr, "Invalid input...???\n");
            return -1;
         }
        copy = malloc(length + 1);
        if (copy != NULL)
         {
            memcpy(copy, head, length);
            copy[length] = '\0';

            printf("*%s*\n", copy);
            /* If you are not going to keep it, free it */
            free(copy);
         }
        head += length; /* <-- this is the imprtant thing */
        n++;
    }
    return 0;
}

非常感谢您的帮助。 - Syvil San Pablo
我可以问一下,在程序的哪个变量和哪个部分提取了第一个单词并得到了结果吗?我想把每个字符串放入一个数组中,以便稍后在代码中使用。 - Syvil San Pablo
你可以在 /* 如果你不打算保留它,就释放它 */ 中通过不释放指针并将其存储在某个地方来实现。 - Iharob Al Asimi
当我执行 memcpy(meti[a].item, copy, length); 在 copy[length] ='\0'; 之后,它只复制程序的最后一个结果,或者换句话说,最后一个<item> </item>标签中包含的最后一个字符串。为什么它直接到最后一个?我需要将从第一个到最后一个提取的每个字符串复制到数组中,以便稍后printf它们。请帮忙。 - Syvil San Pablo

1

在这一行上:

ret = strstr(feed, needle)+6;

你总是从 feed 字符串的开头开始搜索。你需要将不同的起始点传递给 strstr,而你已经在 ter 中有了这个起始点。所以你应该能够像这样做:
ter = feed;
while (ter != NULL) 
{
     ret = strstr(ter, needle) + 6;
...

通过这种方式,您的搜索将会在feed字符串中继续向下移动。

您的代码中还存在一些问题:

  1. strstr()如果找不到匹配项,会返回NULL - 您需要检查该情况,否则程序将崩溃。
  2. 您需要free()您使用malloc()分配的内存。
  3. 如@iharob所指出的"不要对malloc()进行强制转换"

非常感谢您的帮助。 - Syvil San Pablo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接