在C中从字符串中删除子字符串

7
我想从一个字符串中删除特定的子字符串,例如我的主字符串是"ababccdabce",我想要将其中的"abc"删除,使其变为"abcde"
我只想知道在C语言中是否有预定义的函数可以做到这一点,如果没有,该如何实现?

2
你为什么使用C++标签? - user2672107
1
我建议您使用您的问题标题尝试在Google上搜索。 - Code-Apprentice
1
预定义函数在C中。 --> 不是。 - chux - Reinstate Monica
1
可能是在C语言中替换字符串的函数是什么?的重复问题。 - McMillan Cheng
1个回答

11

C语言中没有预定义的函数可以从字符串中删除给定的子字符串,但是您可以使用 strstrmemmove 来编写一个函数。请注意,如果您在原地删除子字符串,则不能使用 memcpystrcpy,因为如果源和目标数组重叠,这些函数的行为是未定义的。

以下是代码:

#include <string.h>

char *strremove(char *str, const char *sub) {
    size_t len = strlen(sub);
    if (len > 0) {
        char *p = str;
        while ((p = strstr(p, sub)) != NULL) {
            memmove(p, p + len, strlen(p + len) + 1);
        }
    }
    return str;
}

请注意,生成的字符串可能包含子字符串,就像您的示例中一样。

Netherwire 提出了一个优化建议:

char *strremove(char *str, const char *sub) {
    size_t len = strlen(sub);
    if (len > 0) {
        char *p = str;
        size_t size = 0;
        while ((p = strstr(p, sub)) != NULL) {
            size = (size == 0) ? (p - str) + strlen(p + len) + 1 : size - len;
            memmove(p, p + len, size - (p - str));
        }
    }
    return str;
}

在进一步完善代码的过程中,我使用了2个手指的方法,创造出了更加高效的版本:仅仅复制第一个匹配项之后的匹配项之间的片段。

char *strremove(char *str, const char *sub) {
    char *p, *q, *r;
    if (*sub && (q = r = strstr(str, sub)) != NULL) {
        size_t len = strlen(sub);
        while ((r = strstr(p = r + len, sub)) != NULL) {
            memmove(q, p, r - p);
            q += r - p;
        }
        memmove(q, p, strlen(p) + 1);
    }
    return str;
}

这里是同样的方法,没有调用memmove

char *strremove(char *str, const char *sub) {
    char *p, *q, *r;
    if (*sub && (q = r = strstr(str, sub)) != NULL) {
        size_t len = strlen(sub);
        while ((r = strstr(p = r + len, sub)) != NULL) {
            while (p < r)
                *q++ = *p++;
        }
        while ((*q++ = *p++) != '\0')
            continue;
    }
    return str;
}

1
您可以通过缓存字符串长度并在每次删除子字符串后减少它来减少strlen调用的次数。 - Netherwire
@Netherwire:说得好,但这会使代码更加繁琐,特别是如果想要避免在没有匹配的情况下计算 strlen(str)。感谢你挑战我...我找到了一个更好的解决方案 :) - chqrlie
信号:SIGSEGV(段错误) - r1v3n
@r1v3n:我修复了sub为空字符串的特殊情况。可能还有其他错误,你能更具体地告诉我哪些参数导致了段错误吗? - chqrlie

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