Finding and replacing c-style strings in C ++

I am trying to write a function that takes three c-style strings and returns a c-style string. This function searches for a c-string for all occurrences of the substring and replaces them with another string.
This program works, but it seems very inelegant. I cannot help but feel how this could have been done in a less bulky way.

char* replaceSubstring(char *original, char *from, char *to)
{
     int origlen = strlen(original);
     int i = 0;
     int count = 0;
     char *ptr;

     //figure out how many times the sub-string occurs in a string.
     //i couldn't figure out a way to avoid this loop
     while (i<origlen)
     {
           ptr = strstr(original+i, from);
           if (!ptr)
               break;
           else
           {
               i = ptr - original + 1;
               count++;
           }
     }
     //figure out what the size of the output string has to be
     int newsize = origlen + (strlen(to) - strlen(from)) * count;

     char *newstring = new char[newsize];  
     newstring[0] = '\0';  
     i = 0;
     while (i < origlen)
     {
          ptr = strstr(original+i, from);
          if (!ptr)
          {
               strcat(newstring,original+i);
               break;
          }
          else
          {
               //this looks extremely ugly and bulky...
               strncat(newstring, original+i, ptr-(original+i));
               strcat(newstring, to);
               i = i + ptr - (original + i) + strlen(from);
          }
     }
     strcat(newstring,"\0");
     return newstring;
}

Anyone have suggestions on how to make this code more understandable and / or more efficient? Any comments are welcome. Please do not suggest using the class string instead. This is not an option. The function should work with c-lines

+3
source share
4 answers

, , , ,

  • , , .
  • , ( STL, ; , std::vector std::list std::deque).
  • , .
  • , .
  • , .

, , , , , , . , ( , /), ( ).


EDIT:

, . , , - - , . (, , .)

char* strreplace(const char* haystack, const char* needle, const char* replacement) {
    // using deque for pop_front
    std::deque<const char*> positions;
    unsigned int haystacklen    = strlen(haystack),
                 needlelen      = strlen(needle),
                 replacementlen = strlen(replacement);

    for (const char* cur = haystack, *pos = strstr(cur, needle); pos; cur = pos + 1, pos = strstr(cur, needle))
        positions.push_back(pos);

    char* newstr    = new char[haystacklen + replacementlen * positions.size() + 1],
          dst       = newstr;
    const char* src = haystack;

    while (src <= haystack + haystacklen)
        if (!positions.empty() && src == positions.front()) {
            strcpy(dst, replacement);
            dst += replacementlen;
            src += needlelen;
            positions.pop_front();
        } else
            *dst++ = *src++;

    return newstr;
}

delete[] .

. , while, , positions.empty() , , , strcpy , , positions.empty() , . , , .

, std::list std::deque, , , .

ildjarn, list deque, size, , , O(1) ( O(n)) pre-++ 11, deque size .

+3

, , .

:

int newsize = origlen + (strlen(to) - strlen(from)) * origlen/strlen(from);

, strlen (from) (, srtlen_from) .

0

, , ( .. ) ( , ):

#include <cstring>
#include <cstdlib>
#include <iostream>

char* replaceSubstring(char *original, char *from, char *to)
{
// This could be improved (I was lazy and made an array twice the size)
    char* retstring = new char[std::strlen(original) * 2];

    int pos = 0;
    for (int i = 0; *(original + i); ++i)
    {   
        if (*(original + i) == *(from)) 
        {
            // Got a match now check if the two are the same
            bool same = true; // Assume they are the same
            for (int j = 1, k = i + 1; *(from + j) && *(original + k); ++j, ++k)
            {
                if (*(from + j) != *(original + k))
                {
                    same = false;
                    break;
                }
            }
            if (same)
            {
                // They are the same now copy to new array
                for (int j = 0; *(to + j); ++j)
                {
                    retstring[pos++] = *(to + j);
                }
                i += std::strlen(from) - 1;
                continue;
            }
        }
        retstring[pos++] = *(original + i);
    }
    retstring[pos] = '\0';
    return retstring;
}

int main()
{
    char orig1[] = "Replace all the places that say all";
    char* r1 = replaceSubstring(orig1, "all", "Replacement");
    std::cout << r1 << std::endl;
    delete [] r1;

    char orig2[] = "XXXXXX with something else XXXXXX";
    char* r2 = replaceSubstring(orig2, "XXXXXX", "hello");
    std::cout << r2 << std::endl;
    delete [] r2;
}
0

Self-extracting: http://ideone.com/ew5pL

This is what seems ugly and cumbersome - no C functions other than strlen and memcpy at the end.

I think yours looks beautiful and compact.

0
source

All Articles