Home > Back-end >  how to substitute substring with different length in C?
how to substitute substring with different length in C?

Time:11-25

Situation as following: In the first line input a string, then the following lines are 'command'. 2 types of command 'p' and 's', 'p' means printing the string, 's' means substitution. e.g. Input a string aaabbbcccqwerdd then input sbqwerbkkk (s means substitution, b acts as a delimiter, therefore it means replacing qwer in the string with kkk) The expected result should be aaabbbccckkkdd, but instead I got aaabbbccckkkrdd Any help?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXLEN 1023
int main() {
    char str[MAXLEN];
    scanf("%s", str);
    char command[MAXLEN];
    while (scanf("%s", command) != EOF) {
        if (command[0] == 'p') {
            printf("%s\n", str); }
        else if (command[0] == 's') {
            char delimiter[] = {"0"};
            strncpy(delimiter, command 1, 1);
            char *a = command;
            a = strtok(command, delimiter);
            a = strtok(NULL, delimiter);
            char *b = command;
            b = strtok(NULL, delimiter);
            int alength = strlen(a);
            int blength = strlen(b);
            char *bereplaced = strstr(str, a);
            if (bereplaced == NULL) {
                continue; }
            int aindex = bereplaced - str;
            strncpy(str   aindex, b, blength);
        }
    }
    return 0;
}

CodePudding user response:

Many things can go wrong here but the main issue is copying from from source string on to itself, there can be memory overlap. Instead declare a new buffer for the result for find/replace operation.

You can define a separate find_replace function as follows:

char* find_replace(const char* src, const char* find, const char* replace)
{
    if (!src) return NULL;
    char* find_ptr = strstr(src, find); if (!find_ptr) return NULL;
    int find_start = find_ptr - src;
    int find_length = strlen(find);
    char* result = malloc(strlen(src)   strlen(replace)   1);
    strncpy(result, src, find_start);
    strcpy(result   find_start, replace);
    strcat(result, find_ptr   find_length);
    return result;
}

int main() 
{
    char source[] = "aaabbbcccqwerdd";
    char command[] = "sbqwerbkkk";
    if (command[0] != 's') return 0;
    char delimiter[] = { "0" };
    delimiter[0] = command[1];

    char* find = strtok(command, delimiter); if (!find) return 0;
    find = strtok(NULL, delimiter); if (!find) return 0;

    char* replace = strtok(NULL, delimiter); if (!replace) return 0;
    char* result = find_replace(source, find, replace);
    if (!result) return 0;
    printf("%s\n", result);
    free(result);
    return 0;
}

CodePudding user response:

Here is another solution. It does the substitution directly into the input string by:

  1. Use memmove to move the trailing part of the orginal string to its final location

  2. Use strncpy to copy the substitute substring to its final location

Like:

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

#define MAXLEN 1023

int main(void) 
{
    char str[MAXLEN] = "aaabbbcccqwerdd";
    char command[MAXLEN] = "sbqwerbkkk";
    printf("COMMAND      : %s\n", command);
    printf("TEXT BEFORE  : %s\n", str);

    char* pfind = command   2;                  // skip initial sb
    char* psub = strchr(pfind, 'b');            // find delimiter
    *psub = '\0';                               // terminate replace string
      psub;                                     // point to substitute substring
    size_t flen = strlen(pfind);                // calculate length
    size_t slen = strlen(psub);                 // calculate length
    char* p = strstr(str, pfind);               // find location of replace string
    size_t sc = strlen(p);                      // calculate length
    memmove(p   slen, p   flen, sc - flen   1); // Move trailing part
    strncpy(p, psub, slen);                     // Put in substitute substring
    
    printf("TEXT AFTER   : %s\n", str);

    return 0;
}

Output:

COMMAND      : sbqwerbkkk
TEXT BEFORE  : aaabbbcccqwerdd
TEXT AFTER   : aaabbbccckkkdd

Disclamer

In order to keep the code example short, the above code blindly trust that the command and the original string form a legal substitution and that there are sufficient memory for the result.

In real code, you need to check that. For instance check that strchr and strstr doesn't return NULL.

  • Related