Trouble with C Code for Case-Insensitive Substring Removal in a String

102 views Asked by At
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

int erase_once(char *input_string, const char *substring, int case_sensitive) {
    size_t string_length = strlen(input_string);
    size_t substring_length = strlen(substring);

    if (string_length < substring_length || substring_length == 0) return 0;

    size_t i;
    for (i = 0; i < string_length - substring_length + 1; i++) {
        int match_found = 1;

        for (size_t j = i; j < i + substring_length; j++) {
            if ((case_sensitive == 0 &&
                 tolower(input_string[j]) != tolower(substring[j-i])) ||
                input_string[j] != substring[j-i]) {
                match_found = 0;
                break;
            }
        }

        if (!match_found) continue;

        for (; i < string_length - substring_length; i++) {
            input_string[i] = input_string[i + substring_length];
        }
        input_string[i] = '\0';

        return 1;
    }

    return 0;
}

int erase(char *input_string, const char *substring, int case_sensitive) {
    int count;
    for (count = 0; erase_once(input_string, substring, case_sensitive); count++);
    return count;
}

int main(void) {
    char main_string[] = "abcdef cde AbCDE";
    const char *substring_to_erase = "abc";

    erase(main_string, substring_to_erase, 0);
    printf("%s\n", main_string);

    return 0;
}

I tryed to make it case sensitive by putting the variable int case_sensitive; and when that wariable is 0 it is not sensitive and when it is 1 it is case sensitive so for example: for input "abcdef cde AbCDE" and substring "abc" if it is 1 it should return -"def cde AbCDE"; and for the same input and case_sensitive set to 0 it should return "def cde DE" another example is for string xYXyXYXY and substring xy and sensitive set to 0 it should return an empty string

but it doesnt, can you help me find the mistake?

3

There are 3 answers

3
gulpr On BEST ANSWER

Split the task into smaller bits

int strneq(const char *s1, const char *s2, size_t n, int cs)
{
    char c1 = 0, c2 = 0;
    while(n-- && *s1 && *s2)
    {
        if(cs)
        {
            c1 = *s1;
            c2 = *s2;
        }
        else
        {
            c1 = tolower(*s1);
            c2 = tolower(*s2);
        }
        if(c1 != c2) break;
        s1++;
        s2++;
    }
    return !(c1 == c2);
}

char *mystrstr(const char *s, const char *find, int cs)
{
    size_t slen = strlen(s);
    size_t flen = strlen(find);
    char *result = NULL;
    if(slen >= flen)
    for(size_t index = 0; index <= slen - flen; index++)
    {
        if(!strneq(s + index, find, slen - index  + 1, cs))
        {
            result = (char *)(s + index);
            break;
        }
    }
    return result;
}

char *strrem(char *haystack, const char *needle, int cs)
{
    size_t nlen = strlen(needle);
    size_t hlen = strlen(haystack);
    char *current;
    while((current = mystrstr(haystack, needle, cs)))
    {
        while((*current = *(current + nlen))) current++;
    }
    return haystack;
}

int main(void)
{
    char h[] = "abcdef cde AbCDE";
    char *n = "abc";

    printf("'%s'\n", strrem(h,n,0));
}

https://godbolt.org/z/M7bh8Pq7a

0
shadow On

you have just forget to check if case_sensitive==1, other wise it will always the second half of your 'if condition' will be checked and considered. this is the line you need to edit

if ((case_sensitive == 0 &&
                 tolower(input_string[j]) != tolower(substring[j-i])) ||
                (case_sensitive == 1 &&
                input_string[j] != substring[j-i]))

note: you have complicated the solution too much, and your code isn't clean enough, those tricks will help you to identify any problem and make it easy for you to debug

1
NoUserNoName On

Everything inside 1 function:

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

int erase(char* input_string, const char* substring, int case_sensitive) {
    int len1 = strlen(input_string),
        len2 = strlen(substring);

    if (len1 < len2 || len1 < 0) return 0;

    int eraseCount = 0,
        N = len1 - len2 + 1;
    
    for (int i = 0; i < N;) {
        int found = 1;
        
        for (int j = 0; j < len2; j++) {
            char c1 = input_string[i + j], c2 = substring[j];
            
            if(( case_sensitive && tolower(c1) != tolower(c2)) || //case_sensitive == 0 - false, otherwise true (any value)
               (!case_sensitive && c1 != c2)) {
                    found = 0;
                    i += j;
                    break;
            } 
        }
        
        if(found) {
            eraseCount++;
            
            for(int j = i; j < N; j++)
                input_string[j] = input_string[j + len2]; //move left
            for(int j = N + len2 - 2; j >= N - 1; j--)
                input_string[j] = 0; //removed
            
            N -= len2;
        } else i++;
    }
    
    return eraseCount;
}

void test1(){
    char main_string[] = "abcdef cde AbCDE";
    const char *substring_to_erase = "abc";
    erase(main_string, substring_to_erase, 0);
    printf("String: \"%s\"\n", main_string);
}

void test2(){
    char main_string[] = "xYXyXYXY";
    const char *substring_to_erase = "xy";
    erase(main_string, substring_to_erase, 1);
    printf("String: \"%s\"\n", main_string);
}

int main(void) {
    test1();
    test2();
    return 0;
}

Result:

String: "def cde AbCDE"
String: ""


...Program finished with exit code 0
Press ENTER to exit console.