Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I couldn't find an implementation of search/replace in C that I liked so I present here my own. It does not use things like strstr(), snprintf(), arbitrary length temporary buffers, etc. It only requires that the haystack buffer is large enough to hold the resulting string after replacements are made.</p> <pre><code>// str_replace(haystack, haystacksize, oldneedle, newneedle) -- // Search haystack and replace all occurences of oldneedle with newneedle. // Resulting haystack contains no more than haystacksize characters (including the '\0'). // If haystacksize is too small to make the replacements, do not modify haystack at all. // // RETURN VALUES // str_replace() returns haystack on success and NULL on failure. // Failure means there was not enough room to replace all occurences of oldneedle. // Success is returned otherwise, even if no replacement is made. char *str_replace(char *haystack, size_t haystacksize, const char *oldneedle, const char *newneedle); // ------------------------------------------------------------------ // Implementation of function // ------------------------------------------------------------------ #define SUCCESS (char *)haystack #define FAILURE (void *)NULL static bool locate_forward(char **needle_ptr, char *read_ptr, const char *needle, const char *needle_last); static bool locate_backward(char **needle_ptr, char *read_ptr, const char *needle, const char *needle_last); char *str_replace(char *haystack, size_t haystacksize, const char *oldneedle, const char *newneedle) { size_t oldneedle_len = strlen(oldneedle); size_t newneedle_len = strlen(newneedle); char *oldneedle_ptr; // locates occurences of oldneedle char *read_ptr; // where to read in the haystack char *write_ptr; // where to write in the haystack const char *oldneedle_last = // the last character in oldneedle oldneedle + oldneedle_len - 1; // Case 0: oldneedle is empty if (oldneedle_len == 0) return SUCCESS; // nothing to do; define as success // Case 1: newneedle is not longer than oldneedle if (newneedle_len &lt;= oldneedle_len) { // Pass 1: Perform copy/replace using read_ptr and write_ptr for (oldneedle_ptr = (char *)oldneedle, read_ptr = haystack, write_ptr = haystack; *read_ptr != '\0'; read_ptr++, write_ptr++) { *write_ptr = *read_ptr; bool found = locate_forward(&amp;oldneedle_ptr, read_ptr, oldneedle, oldneedle_last); if (found) { // then perform update write_ptr -= oldneedle_len; memcpy(write_ptr+1, newneedle, newneedle_len); write_ptr += newneedle_len; } } *write_ptr = '\0'; return SUCCESS; } // Case 2: newneedle is longer than oldneedle else { size_t diff_len = // the amount of extra space needed newneedle_len - // to replace oldneedle with newneedle oldneedle_len; // in the expanded haystack // Pass 1: Perform forward scan, updating write_ptr along the way for (oldneedle_ptr = (char *)oldneedle, read_ptr = haystack, write_ptr = haystack; *read_ptr != '\0'; read_ptr++, write_ptr++) { bool found = locate_forward(&amp;oldneedle_ptr, read_ptr, oldneedle, oldneedle_last); if (found) { // then advance write_ptr write_ptr += diff_len; } if (write_ptr &gt;= haystack+haystacksize) return FAILURE; // no more room in haystack } // Pass 2: Walk backwards through haystack, performing copy/replace for (oldneedle_ptr = (char *)oldneedle_last; write_ptr &gt;= haystack; write_ptr--, read_ptr--) { *write_ptr = *read_ptr; bool found = locate_backward(&amp;oldneedle_ptr, read_ptr, oldneedle, oldneedle_last); if (found) { // then perform replacement write_ptr -= diff_len; memcpy(write_ptr, newneedle, newneedle_len); } } return SUCCESS; } } // locate_forward: compare needle_ptr and read_ptr to see if a match occured // needle_ptr is updated as appropriate for the next call // return true if match occured, false otherwise static inline bool locate_forward(char **needle_ptr, char *read_ptr, const char *needle, const char *needle_last) { if (**needle_ptr == *read_ptr) { (*needle_ptr)++; if (*needle_ptr &gt; needle_last) { *needle_ptr = (char *)needle; return true; } } else *needle_ptr = (char *)needle; return false; } // locate_backward: compare needle_ptr and read_ptr to see if a match occured // needle_ptr is updated as appropriate for the next call // return true if match occured, false otherwise static inline bool locate_backward(char **needle_ptr, char *read_ptr, const char *needle, const char *needle_last) { if (**needle_ptr == *read_ptr) { (*needle_ptr)--; if (*needle_ptr &lt; needle) { *needle_ptr = (char *)needle_last; return true; } } else *needle_ptr = (char *)needle_last; return false; } </code></pre> <h2>Example usage</h2> <pre><code>#define BUF 30 char *retval1, *retval2; char message[BUF] = "Your name is $USERNAME."; char username[] = "admin"; char username_toolong[] = "System Administrator"; int main() { retval1 = str_replace(message, BUF, "$USERNAME", username_toolong); retval2 = str_replace(message, BUF, "$USERNAME", username); if (!retval1) printf("Not enough room to replace $USERNAME with `%s'\n", username_toolong); if (!retval2) printf("Not enough room to replace $USERNAME with `%s'\n", username); printf("%s\n", message); return 0; } </code></pre> <h2>Output</h2> <blockquote> <p>Not enough room to replace $USERNAME with `System Administrator'<br /> Your name is admin.</p> </blockquote> <p>Cheers.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload