-1

Let's say I have a string which contains the following text:

#Line1 Hello, today I ate 3 crackers for dinner
#Line2 and 4 crackers with some soup for lunch.
#Line3 For breakfast tomorrow, I plan on eating
#Line4 bacon, eggs, and ham.

and I wanted to cut the part of the string from one substring to another substring, for example from "#Line3" to \n to get the following output:

#Line1 Hello, today I ate 3 crackers for dinner
#Line2 and 4 crackers with some soup for lunch.
#Line4 bacon, eggs, and ham.

(Just basically cutting out everything from #Line3 to \n and in essence removing the entire 3rd line)

I have read that this could be done with the function memmove but have not been able to figure out how to correctly do so. However, if anyone has a solution that does not involve memmove, of course that would be equally appreciated.

Here's what I have so far:

int str_cut(char *str, char *begin, int len)
{
    int l = strlen(str);
    if (strlen(begin) + len > l) len = l - begin;
    memmove(str + strlen(begin), str + begin + len, l - len + 1);
    return len;
}

This is so far pretty far off in accomplishing what I want because it depends on knowing the length of what needs to be cut out and what I want it to do is cut out between 2 chars , to go along with my previous example to cut everything between "line3" and \n

3 Answers3

0

Using memcpy you can copy two parts into two buffers and then concat them using strcat.

Get a substring of a char*

Community
  • 1
  • 1
Majeed Siddiqui
  • 548
  • 2
  • 9
0

Pretty easy using memmove:

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

char *
strfilter(const char *str, const char *substr)
{
    char *res = strdup(str), *ptr = NULL;
    size_t len = 0;

    if (!res)
        return NULL;

    ptr = strstr(res, substr);

    if (!ptr)
    {
        free(res);
        return NULL;
    }

    len = strlen(ptr) - strlen(substr);
    memmove(ptr, ptr + strlen(substr), len);
    memset(ptr + len, 0, strlen(ptr + len));

    return res;
}

char *
strfilter2(const char *str, const char *start, const char *end)
{
    char *res = strdup(str), *ptr1 = NULL, *ptr2 = NULL, *tmp = NULL;
    size_t len1 = 0, len2 = 0;

    if (!res)
        return NULL;

    ptr1 = strstr(res, start);
    ptr2 = strstr(res, end);

    if (!ptr1 || !ptr2)
        return NULL;

    if (ptr1 > ptr2)
    {
        tmp = ptr2;
        ptr2 = ptr1;
        ptr1 = tmp;
        tmp = end;
        end = start;
        start = tmp;
    }

    len1 = strlen(start);
    len2 = strlen(ptr2);
    memmove(ptr1 + len1, ptr2, len2);
    memset(ptr1 + len1 + len2, 0, strlen(ptr1 + len1 + len2));

    return res;
}

int
main(void)
{
    const char *str = "Hello, today I ate 3 crackers for dinner\n"
                      "and 4 crackers with some soup for lunch.\n"
                      "For breakfast tomorrow, I plan on eating\n"
                      "bacon, eggs, and ham.\n";
    char *res = strfilter2(str, "and 4 crackers with some soup for lunch.\n", "bacon, eggs, and ham.\n");

    if (!res)
    {
        perror("strfilter2()");
        return 1;
    }

    puts(res);
    free(res);

    return 0;
}

The function just finds the substring that you want to remove and overwrites it with everything that comes after it, and then it zeroes out the remainder of the string.

EDIT: Added strfilter2 to eliminate the content between two substrings.

bkerivan
  • 139
  • 7
0

To cut out a part of the string you need to find - of course - first the start and end marks of the part you want to cut. For that you can use strstr. Then just copy the remaining part (everything after the end mark) to the place where you found the start mark:

char * cut_between(
  char * const str,
  char const * const from,
  char const * const to) {
  char * const startMark = strstr(str, from);
  if (! startMark) {
    return NULL;
  }
  char * const endMark =
    strstr(startMark+strlen(from), to);
  if (endMark) {
    strcpy(startMark, endMark+strlen(to));
    return startMark + strlen(startMark) + 1;
  } else {
    *startMark = '\0';
    return startMark + 1;
  }
}

On success the above function returns a pointer beyond the end of the resulting string. This is useful for buffer compaction, like:

int main() {
  char * const input = malloc(400);
  fgets(input, 400, stdin);
  char const * const end =
    cut_between(input, "from", "to");
  if (end) {
    char const * const result =
      realloc(input, end - input);
    puts(result);
    // OMG missing free(s), well ... OK for this simple test.
  }
  return 0;
}

(Live on ideone)

Please note the missing error checks on above test. In production code these must be added.

Daniel Jour
  • 15,896
  • 2
  • 36
  • 63