Home > Software design >  Remove every repetition of substring with case sensitivity
Remove every repetition of substring with case sensitivity

Time:02-17

I need to remove every repetition of substring from a string but with case sensitivity. When one substring is removed, the process goes again from the beginning of string.

Example:

char text[1000]="abcdef cde AbCDE";what[1000]="abc";cs;

OUTPUT for cs=1: "def cde AbCDE"
OUTPUT for cs=0: "def cde DE"

cs (case sensitive) 1 means care of case sensitivity, while cs 0 means don't care.

#include <ctype.h>
#include <stdio.h>
#include <string.h>
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;
}
char* remove_all_substrings(char* str, const char* text, int cs) {
int i,e=0;
    if(cs==0){
        for(i=0;i<strlen(str);i  )
        str[i]=tolower(str[i]);
    }
       while(1){
           e  ;
           strremove(str, text);
           if(strstr(str,text)==NULL||e==100)break;
       }

  return str;
}
int main() {
   char text[1000] = "abcdef cde AbCDE";;
  char what[1000] = "abc";
  int cs = 1;
  printf("\"%s\"", remove_all_substrings(text, what, cs));
  return 0;
}

I get wrong output for cs=0, because in my approach I convert all characters from string to lowercase and then I remove them. Could you help me modify my code and give me some better approach for solving this task?

  • Note: auxiliary strings are not allowed.

CodePudding user response:

You already know why you are getting wrong output when cs value is 0.

Note that functions strcasecmp() and strncasecmp() are conforming to 4.4BSD, POSIX.1-2001, whereas strcasestr() is a nonstandard extension. These function are not part of C standard. Using these may result in a non-portable code.

You have used tolower() in your code but you are modifying the original string. Instead of modifying the original string, simply compare the return value of tolower() when doing case insensitive comparison.

You can do:

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

char* remove_all_substrings (char * str, const char * str_toremove, int cs) {
    if (str && str_toremove) {
        size_t len = strlen (str_toremove);
        int res = -1;
        char * ptr = str;
        size_t i = 0;

        while (str[i] && len) {
            if (cs) {
                if (str[i] == str_toremove[0]) {
                    res = 0;
                    size_t tmp_len = len;
                    while (--tmp_len) {
                        if (str[i   len - tmp_len] != str_toremove[len - tmp_len]) {
                            res = -1;
                            break;
                        }
                    }
                }
            } else {
                if (tolower (str[i]) == tolower (str_toremove[0])) {
                    res = 0;
                    size_t tmp_len = len;
                    while (--tmp_len) {
                        if (tolower (str[i   len - tmp_len]) != tolower (str_toremove[len - tmp_len])) {
                            res = -1;
                            break;
                        }
                    }
                }
            }
            if (res == 0) {
                i = i   len;
                res = -1;
            } else {
                *ptr   = str[i  ]; 
            }
        }

        if (len) {
            *ptr = '\0';
        }
    }

    return str;
}

void helper_func (char * str, const char * str_toremove, int cs) {
    printf("str : \"%s\", str_toremove : \"%s\", case sensitive : %d\n", 
        str ? str : "(NULL)", str_toremove ? str_toremove : "(NULL)", cs);

    char * res = remove_all_substrings(str, str_toremove, cs);

    printf("res : \"%s\"\n\n", res ? res : "(NULL)");
}

int main (int argc, char * argv[]) {
    if (argc != 2) {
        printf ("Invalid argument\n");
        return 0;
    }

    int cs = atoi (argv[1]);
    if ((cs != 0) && (cs != 1)) {
        printf ("Invalid commmand line argument value\n");
        return 0;
    }

    const char what[] = "abc";

    char text1[] = "abcdef cde AbCDE";;
    helper_func (text1, what, cs);

    char text2[] = "DuMMyabcd AbCDE";;
    helper_func (text2, what, cs);

    char text3[] = "idecbt HYTRg HGB jC";
    helper_func (text3, what, cs);

    char text4[] = "";
    helper_func (text4, what, cs);

    // test : pass NULL to input string pointer
    helper_func (NULL, what, cs);

    char text5[] = "abcDEFGHIABC";
    // test : pass NULL to toremove string pointer
    helper_func (text5, NULL, cs);

    helper_func (text5, "", cs);

    char text6[] = "abcABC";
    helper_func (text6, what, cs);

    char text7[] = "xxXXxx";
    helper_func (text7, "x", cs);

    char text8[] = "aBAcaDAe";
    helper_func (text8, "a", cs);

    return 0;
}

Usage : ./a.out <case_sensitive>
Where value of case_sensitive is 0 or 1. 0 means case insensitive removal and 1 means case sensitive removal.

Output - Case insensitive removal:

# ./a.out 0 
str : "abcdef cde AbCDE", str_toremove : "abc", case sensitive : 0
res : "def cde DE"

str : "DuMMyabcd AbCDE", str_toremove : "abc", case sensitive : 0
res : "DuMMyd DE"

str : "idecbt HYTRg HGB jC", str_toremove : "abc", case sensitive : 0
res : "idecbt HYTRg HGB jC"

str : "", str_toremove : "abc", case sensitive : 0
res : ""

str : "(NULL)", str_toremove : "abc", case sensitive : 0
res : "(NULL)"

str : "abcDEFGHIABC", str_toremove : "(NULL)", case sensitive : 0
res : "abcDEFGHIABC"

str : "abcDEFGHIABC", str_toremove : "", case sensitive : 0
res : "abcDEFGHIABC"

str : "abcABC", str_toremove : "abc", case sensitive : 0
res : ""

str : "xxXXxx", str_toremove : "x", case sensitive : 0
res : ""

str : "aBAcaDAe", str_toremove : "a", case sensitive : 0
res : "BcDe"

Output - Case sensitive removal:

# ./a.out 1
str : "abcdef cde AbCDE", str_toremove : "abc", case sensitive : 1
res : "def cde AbCDE"

str : "DuMMyabcd AbCDE", str_toremove : "abc", case sensitive : 1
res : "DuMMyd AbCDE"

str : "idecbt HYTRg HGB jC", str_toremove : "abc", case sensitive : 1
res : "idecbt HYTRg HGB jC"

str : "", str_toremove : "abc", case sensitive : 1
res : ""

str : "(NULL)", str_toremove : "abc", case sensitive : 1
res : "(NULL)"

str : "abcDEFGHIABC", str_toremove : "(NULL)", case sensitive : 1
res : "abcDEFGHIABC"

str : "abcDEFGHIABC", str_toremove : "", case sensitive : 1
res : "abcDEFGHIABC"

str : "abcABC", str_toremove : "abc", case sensitive : 1
res : "ABC"

str : "xxXXxx", str_toremove : "x", case sensitive : 1
res : "XX"

str : "aBAcaDAe", str_toremove : "a", case sensitive : 1
res : "BAcDAe"

CodePudding user response:

You have written strremove to be case-sensitive (although "case-strict" might be a better term).

If you want to remove instances of a substring in a case-insensitive way, you cannot achieve that by modifying the substring and passing that to a case-sensitive function (unless you are willing to iterate over all possible case-permutations of the substring). You could make a copy of str, convert that to lower case, find the instances of sub, then use those locations to remove the substrings in the original str, but I suppose that might break the rule against auxiliary strings.

You must write a case-insensitive version of strremove. Which is not difficult; just use strcasestr instead of strstr.

But before you do that, you might change what strremove returns. As it stands, strremove accepts a pointer to the string, modifies the string, and then returns the pointer, which it never modified. The returned value is redundant, and in fact the calling code doesn't even retain it, so the function might just as well return void. I suggest it return a bool indicating whether it found (and removed) an instance of the substring; that way you could do without the awkward searching by remove_all_substrings.

  • Related