it-swarm.com.de

Was ist die Funktion, um String in C zu ersetzen?

Bei einer Zeichenfolge (Zeichenfolge *) möchte ich alle Vorkommen einer Teilzeichenfolge suchen und durch eine alternative Zeichenfolge ersetzen. Ich sehe keine einfache Funktion, die dies in <string.h> erreicht

77
Eun-Gyu Kim

Das Optimierungsprogramm sollte die meisten lokalen Variablen entfernen. Der tmp-Zeiger sorgt dafür, dass strcpy nicht die Zeichenfolge durchlaufen muss, um die Null zu finden. tmp zeigt nach jedem Aufruf auf das Ende des Ergebnisses. (Siehe Shlemiel the Painter's Algorithmus , warum strcpy nervig sein kann.)

// You must free the result if result is non-NULL.
char *str_replace(char *orig, char *rep, char *with) {
    char *result; // the return string
    char *ins;    // the next insert point
    char *tmp;    // varies
    int len_rep;  // length of rep (the string to remove)
    int len_with; // length of with (the string to replace rep with)
    int len_front; // distance between rep and end of last rep
    int count;    // number of replacements

    // sanity checks and initialization
    if (!orig || !rep)
        return NULL;
    len_rep = strlen(rep);
    if (len_rep == 0)
        return NULL; // empty rep causes infinite loop during count
    if (!with)
        with = "";
    len_with = strlen(with);

    // count the number of replacements needed
    ins = orig;
    for (count = 0; tmp = strstr(ins, rep); ++count) {
        ins = tmp + len_rep;
    }

    tmp = result = malloc(strlen(orig) + (len_with - len_rep) * count + 1);

    if (!result)
        return NULL;

    // first time through the loop, all the variable are set correctly
    // from here on,
    //    tmp points to the end of the result string
    //    ins points to the next occurrence of rep in orig
    //    orig points to the remainder of orig after "end of rep"
    while (count--) {
        ins = strstr(orig, rep);
        len_front = ins - orig;
        tmp = strncpy(tmp, orig, len_front) + len_front;
        tmp = strcpy(tmp, with) + len_with;
        orig += len_front + len_rep; // move to next "end of rep"
    }
    strcpy(tmp, orig);
    return result;
}
71
jmucchiello

Dies ist in der Standard-C-Bibliothek nicht enthalten, da nur mit einem Zeichen * der der Zeichenfolge zugewiesene Speicher nicht erhöht werden kann, wenn die Ersatzzeichenfolge länger ist als die ersetzte Zeichenfolge.

Sie können dies mit std :: string einfacher tun, aber selbst dort wird keine einzige Funktion dies für Sie tun.

20
Don Neufeld

Da Strings in C nicht dynamisch wachsen können, funktioniert Inplace-Substitution im Allgemeinen nicht. Daher müssen Sie Platz für eine neue Zeichenfolge zuweisen, die ausreichend Platz für Ihre Ersetzung hat, und dann die Teile aus dem Original plus Ersetzung in die neue Zeichenfolge kopieren. Um die Teile zu kopieren, verwenden Sie strncpy .

9
lothar

Sie können eine eigene Ersetzungsfunktion erstellen, indem Sie strstr verwenden, um die Teilstrings zu finden, und strncpy, um Teile in einen neuen Puffer zu kopieren. 

Wenn Sie nicht möchten, dass replace_with dieselbe Länge hat wie Sie replace möchten, ist es wahrscheinlich am besten, einen neuen Puffer zu verwenden, um die neue Zeichenfolge zu kopieren.

8
Brian R. Bondy

Es gibt keine.

Sie müssen Ihren eigenen Wurf mit etwas wie strstr und strcat oder strcpy machen.

8
Reed Copsey

Hier ist ein Beispielcode, der es tut. 

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

char * replace(
    char const * const original, 
    char const * const pattern, 
    char const * const replacement
) {
  size_t const replen = strlen(replacement);
  size_t const patlen = strlen(pattern);
  size_t const orilen = strlen(original);

  size_t patcnt = 0;
  const char * oriptr;
  const char * patloc;

  // find how many times the pattern occurs in the original string
  for (oriptr = original; patloc = strstr(oriptr, pattern); oriptr = patloc + patlen)
  {
    patcnt++;
  }

  {
    // allocate memory for the new string
    size_t const retlen = orilen + patcnt * (replen - patlen);
    char * const returned = (char *) malloc( sizeof(char) * (retlen + 1) );

    if (returned != NULL)
    {
      // copy the original string, 
      // replacing all the instances of the pattern
      char * retptr = returned;
      for (oriptr = original; patloc = strstr(oriptr, pattern); oriptr = patloc + patlen)
      {
        size_t const skplen = patloc - oriptr;
        // copy the section until the occurence of the pattern
        strncpy(retptr, oriptr, skplen);
        retptr += skplen;
        // copy the replacement 
        strncpy(retptr, replacement, replen);
        retptr += replen;
      }
      // copy the rest of the string.
      strcpy(retptr, oriptr);
    }
    return returned;
  }
}

#include <stdio.h>
int main(int argc, char * argv[])
{
  if (argc != 4)
  {
    fprintf(stderr,"usage: %s <original text> <pattern> <replacement>\n", argv[0]);
    exit(-1);
  }
  else
  {
    char * const newstr = replace(argv[1], argv[2], argv[3]);
    if (newstr)
    {
      printf("%s\n", newstr);
      free(newstr);
    }
    else
    {
      fprintf(stderr,"allocation error\n");
      exit(-2);
    }
  }
  return 0;
}
8
rampion
// Here is the code for unicode strings!


int mystrstr(wchar_t *txt1,wchar_t *txt2)
{
    wchar_t *posstr=wcsstr(txt1,txt2);
    if(posstr!=NULL)
    {
        return (posstr-txt1);
    }else
    {
        return -1;
    }
}

// assume: supplied buff is enough to hold generated text
void StringReplace(wchar_t *buff,wchar_t *txt1,wchar_t *txt2)
{
    wchar_t *tmp;
    wchar_t *nextStr;
    int pos;

    tmp=wcsdup(buff);

    pos=mystrstr(tmp,txt1);
    if(pos!=-1)
    {
        buff[0]=0;
        wcsncpy(buff,tmp,pos);
        buff[pos]=0;

        wcscat(buff,txt2);

        nextStr=tmp+pos+wcslen(txt1);

        while(wcslen(nextStr)!=0)
        {
            pos=mystrstr(nextStr,txt1);

            if(pos==-1)
            {
                wcscat(buff,nextStr);
                break;
            }

            wcsncat(buff,nextStr,pos);
            wcscat(buff,txt2);

            nextStr=nextStr+pos+wcslen(txt1);   
        }
    }

    free(tmp);
}
4

Die Funktion repl_str () auf creativeandcritical.net ist schnell und zuverlässig. Ebenfalls auf dieser Seite enthalten ist eine breite Zeichenfolgevariante repl_wcs () , die mit Unicode-Zeichenfolgen verwendet werden kann, einschließlich der in UTF-8 über Hilfefunktionen codierten Zeichen. Der Demo-Code wird auf der Seite verlinkt. Verspätete vollständige Offenlegung: Ich bin der Autor dieser Seite und der darauf befindlichen Funktionen.

3
Laird

ich finde die meisten der vorgeschlagenen Funktionen schwer zu verstehen - also kam ich dazu:

static char *dull_replace(const char *in, const char *pattern, const char *by)
{
    size_t outsize = strlen(in) + 1;
    // TODO maybe avoid reallocing by counting the non-overlapping occurences of pattern
    char *res = malloc(outsize);
    // use this to iterate over the output
    size_t resoffset = 0;

    char *needle;
    while (needle = strstr(in, pattern)) {
        // copy everything up to the pattern
        memcpy(res + resoffset, in, needle - in);
        resoffset += needle - in;

        // skip the pattern in the input-string
        in = needle + strlen(pattern);

        // adjust space for replacement
        outsize = outsize - strlen(pattern) + strlen(by);
        res = realloc(res, outsize);

        // copy the pattern
        memcpy(res + resoffset, by, strlen(by));
        resoffset += strlen(by);
    }

    // copy the remaining input
    strcpy(res + resoffset, in);

    return res;
}

die Ausgabe muss frei sein

3
yogo1212
/*замена символа в строке*/
char* replace_char(char* str, char in, char out) {
    char * p = str;

    while(p != '\0') {
        if(*p == in)
            *p == out;
        ++p;
    }

    return str;
}
1
qwerty ytrewq

Hier ist der, den ich basierend auf diesen Anforderungen erstellt habe:

  1. Ersetzen Sie das Muster unabhängig davon, ob es lang oder kürzer ist.

  2. Verwenden Sie kein Malloc (explizit oder implizit), um Speicherverluste zu vermeiden.

  3. Ersetzen Sie eine beliebige Anzahl von Vorkommen eines Musters.

  4. Tolerieren Sie die Ersetzungszeichenfolge, deren Teilzeichenfolge der Suchzeichenfolge entspricht.

  5. Muss nicht überprüfen, ob das Line-Array ausreichend groß ist, um den Ersatz zu halten. z.B. Dies funktioniert nur, wenn der Anrufer weiß, dass die Leitung ausreichend groß ist, um die neue Zeichenfolge aufzunehmen.

/* returns number of strings replaced.
*/
int replacestr(char *line, const char *search, const char *replace)
{
   int count;
   char *sp; // start of pattern

   //printf("replacestr(%s, %s, %s)\n", line, search, replace);
   if ((sp = strstr(line, search)) == NULL) {
      return(0);
   }
   count = 1;
   int sLen = strlen(search);
   int rLen = strlen(replace);
   if (sLen > rLen) {
      // move from right to left
      char *src = sp + sLen;
      char *dst = sp + rLen;
      while((*dst = *src) != '\0') { dst++; src++; }
   } else if (sLen < rLen) {
      // move from left to right
      int tLen = strlen(sp) - sLen;
      char *stop = sp + rLen;
      char *src = sp + sLen + tLen;
      char *dst = sp + rLen + tLen;
      while(dst >= stop) { *dst = *src; dst--; src--; }
   }
   memcpy(sp, replace, rLen);

   count += replacestr(sp + rLen, search, replace);

   return(count);
}

Vorschläge zur Verbesserung dieses Codes werden mit Freude angenommen. Einfach den Kommentar posten und ich werde es testen. 

1
Michael Potter

Sie können diese Funktion verwenden (die Kommentare erklären, wie es funktioniert):

void strreplace(char *string, const char *find, const char *replaceWith){
    if(strstr(string, replaceWith) != NULL){
        char *temporaryString = malloc(strlen(strstr(string, find) + strlen(find)) + 1);
        strcpy(temporaryString, strstr(string, find) + strlen(find));    //Create a string with what's after the replaced part
        *strstr(string, find) = '\0';    //Take away the part to replace and the part after it in the initial string
        strcat(string, replaceWith);    //Concat the first part of the string with the part to replace with
        strcat(string, temporaryString);    //Concat the first part of the string with the part after the replaced part
        free(temporaryString);    //Free the memory to avoid memory leaks
    }
}
1
Donald Duck
DWORD ReplaceString(__inout PCHAR source, __in DWORD dwSourceLen, __in const char* pszTextToReplace, __in const char* pszReplaceWith)
{
    DWORD dwRC = NO_ERROR;
    PCHAR foundSeq = NULL;
    PCHAR restOfString = NULL;
    PCHAR searchStart = source;
    size_t szReplStrcLen = strlen(pszReplaceWith), szRestOfStringLen = 0, sztextToReplaceLen = strlen(pszTextToReplace), remainingSpace = 0, dwSpaceRequired = 0;
    if (strcmp(pszTextToReplace, "") == 0)
        dwRC = ERROR_INVALID_PARAMETER;
    else if (strcmp(pszTextToReplace, pszReplaceWith) != 0)
    {
        do
        {
            foundSeq = strstr(searchStart, pszTextToReplace);
            if (foundSeq)
            {
                szRestOfStringLen = (strlen(foundSeq) - sztextToReplaceLen) + 1;
                remainingSpace = dwSourceLen - (foundSeq - source);
                dwSpaceRequired = szReplStrcLen + (szRestOfStringLen);
                if (dwSpaceRequired > remainingSpace)
                {
                    dwRC = ERROR_MORE_DATA;
                }

                else
                {
                    restOfString = CMNUTIL_calloc(szRestOfStringLen, sizeof(CHAR));
                    strcpy_s(restOfString, szRestOfStringLen, foundSeq + sztextToReplaceLen);

                    strcpy_s(foundSeq, remainingSpace, pszReplaceWith);
                    strcat_s(foundSeq, remainingSpace, restOfString);
                }

                CMNUTIL_free(restOfString);
                searchStart = foundSeq + szReplStrcLen; //search in the remaining str. (avoid loops when replWith contains textToRepl 
            }
        } while (foundSeq && dwRC == NO_ERROR);
    }
    return dwRC;
}
0
Andy Mazanec
char *replace(const char*instring, const char *old_part, const char *new_part)
{

#ifndef EXPECTED_REPLACEMENTS
    #define EXPECTED_REPLACEMENTS 100
#endif

    if(!instring || !old_part || !new_part)
    {
        return (char*)NULL;
    }

    size_t instring_len=strlen(instring);
    size_t new_len=strlen(new_part);
    size_t old_len=strlen(old_part);
    if(instring_len<old_len || old_len==0)
    {
        return (char*)NULL;
    }

    const char *in=instring;
    const char *found=NULL;
    size_t count=0;
    size_t out=0;
    size_t ax=0;
    char *outstring=NULL;

    if(new_len> old_len )
    {
        size_t Diff=EXPECTED_REPLACEMENTS*(new_len-old_len);
        size_t outstring_len=instring_len + Diff;
        outstring =(char*) malloc(outstring_len); 
        if(!outstring){
            return (char*)NULL;
        }
        while((found = strstr(in, old_part))!=NULL)
        {
            if(count==EXPECTED_REPLACEMENTS)
            {
                outstring_len+=Diff;
                if((outstring=realloc(outstring,outstring_len))==NULL)
                {
                     return (char*)NULL;
                }
                count=0;
            }
            ax=found-in;
            strncpy(outstring+out,in,ax);
            out+=ax;
            strncpy(outstring+out,new_part,new_len);
            out+=new_len;
            in=found+old_len;
            count++;
        }
    }
    else
    {
        outstring =(char*) malloc(instring_len);
        if(!outstring){
            return (char*)NULL;
        }
        while((found = strstr(in, old_part))!=NULL)
        {
            ax=found-in;
            strncpy(outstring+out,in,ax);
            out+=ax;
            strncpy(outstring+out,new_part,new_len);
            out+=new_len;
            in=found+old_len;
        }
    }
    ax=(instring+instring_len)-in;
    strncpy(outstring+out,in,ax);
    out+=ax;
    outstring[out]='\0';

    return outstring;
}
0
fann95

ein Fix für die Antwort von fann95, der die direkte Änderung der Zeichenfolge verwendet und davon ausgeht, dass der Puffer, auf den die Zeile zeigt, groß genug ist, um die resultierende Zeichenfolge aufzunehmen.

static void replacestr(char *line, const char *search, const char *replace)
{
     char *sp;

     if ((sp = strstr(line, search)) == NULL) {
         return;
     }
     int search_len = strlen(search);
     int replace_len = strlen(replace);
     int tail_len = strlen(sp+search_len);

     memmove(sp+replace_len,sp+search_len,tail_len+1);
     memcpy(sp, replace, replace_len);
}
0
byron

Hier geht meins, es ist eigenständig und vielseitig sowie effizient, es wächst oder schrumpft Puffer nach Bedarf in jeder Rekursion

void strreplace(char *src, char *str, char *rep)
{
    char *p = strstr(src, str);
    if (p)
    {
        int len = strlen(src)+strlen(rep)-strlen(str);
        char r[len];
        memset(r, 0, len);
        if ( p >= src ){
            strncpy(r, src, p-src);
            r[p-src]='\0';
            strncat(r, rep, strlen(rep));
            strncat(r, p+strlen(str), p+strlen(str)-src+strlen(src));
            strcpy(src, r);
            strreplace(p+strlen(rep), str, rep);
        }
    }
}
0
Daniel J.
// Replace every occurence of a in str with b

void strrepl(char *str, const char *a, const char *b) {
    for (char *cursor = str; (cursor = strstr(cursor, a)) != NULL;){
        memmove(cursor + strlen(b), cursor + strlen(a), strlen(cursor) - strlen(a) + 1);
        for (int i = 0; b[i] != '\0'; i++)
            cursor[i] = b[i];
        cursor += strlen(b);
    }
}

Dies ist möglicherweise das Beste, was Sie tun können:

  • nur 8 Zeilen
  • nur 1 Zeitzeiger
  • In-Place-Änderung
  • arbeitet mit beliebiger Größe a und bchar*
  • arbeitet zum Löschen

wenn Sie keine In-Place-Änderung wünschen oder mit einem const char* arbeiten müssen, handelt es sich um eine andere Version derselben Funktion, die ein neues Zeichen * mit vorgenommenen Änderungen zurückgibt. (Vergessen Sie nicht, dass free der Rückgabewert ist, da strdup() eine malloc hinter der Szene ausführt.)

char* astrrepl(const char *str, const char *a, const char *b) {
    char* strd = strdup(str);
    for (char *cursor = strd; (cursor = strstr(cursor, a)) != NULL;){
        memmove(cursor + strlen(b), cursor + strlen(a), strlen(cursor) - strlen(a) + 1);
        for (int i = 0; b[i] != '\0'; i++)
            cursor[i] = b[i];
        cursor += strlen(b);
    }
    return strd;
}

Beispielcode :

int main(int argc, char const *argv[])
{
    char *a = strdup("Hello This Is Jack");
    char *b = astrrepl(a, " ", "~~~");
    printf("Out of place modification : %s\n", b);

    strrepl(a, "Jack", "Fourchette");
    printf("In place modification     : %s\n", a);
    return 0;
}

Ausgabe:

Out of place modification : Hello~~~This~~~Is~~~Jack
In place modification     : Hello This Is Fourchette
0
Nitoref

Los geht's .... diese Funktion ersetzt jedes Vorkommen von char x durch char y in der Zeichenkette str

char *zStrrep(char *str, char x, char y){
    char *tmp=str;
    while(*tmp)
        if(*tmp == x)
            *tmp++ = y; /* assign first, then incement */
        else
            *tmp++;

    *tmp='\0';
    return str;
}

Ein Beispiel könnte sein

  Exmaple Usage
        char s[]="this is a trial string to test the function.";
        char x=' ', y='_';
        printf("%s\n",zStrrep(s,x,y));

  Example Output
        this_is_a_trial_string_to_test_the_function.

Die Funktion stammt aus einer string-Bibliothek, die ich auf Github unterhalte , Sie können sich gerne andere verfügbare Funktionen ansehen oder sogar zum Code beitragen :)

https://github.com/fnoyanisi/zString

EDIT: @ Siride ist richtig, die obige Funktion ersetzt nur Zeichen. Schreibe einfach diese, die Zeichenketten ersetzt.

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

/* replace every occurance of string x with string y */
char *zstring_replace_str(char *str, const char *x, const char *y){
    char *tmp_str = str, *tmp_x = x, *dummy_ptr = tmp_x, *tmp_y = y;
    int len_str=0, len_y=0, len_x=0;

    /* string length */
    for(; *tmp_y; ++len_y, ++tmp_y)
        ;

    for(; *tmp_str; ++len_str, ++tmp_str)
        ;

    for(; *tmp_x; ++len_x, ++tmp_x)
        ;

    /* Bounds check */
    if (len_y >= len_str)
        return str;

    /* reset tmp pointers */
    tmp_y = y;
    tmp_x = x;

    for (tmp_str = str ; *tmp_str; ++tmp_str)
        if(*tmp_str == *tmp_x) {
            /* save tmp_str */
            for (dummy_ptr=tmp_str; *dummy_ptr == *tmp_x; ++tmp_x, ++dummy_ptr)
                if (*(tmp_x+1) == '\0' && ((dummy_ptr-str+len_y) < len_str)){
                /* Reached end of x, we got something to replace then!
                * Copy y only if there is enough room for it
                */
                    for(tmp_y=y; *tmp_y; ++tmp_y, ++tmp_str)
                        *tmp_str = *tmp_y;
            }
        /* reset tmp_x */
        tmp_x = x;
        }

    return str;
}

int main()
{
    char s[]="Free software is a matter of liberty, not price.\n"
             "To understand the concept, you should think of 'free' \n"
             "as in 'free speech', not as in 'free beer'";

    printf("%s\n\n",s);
    printf("%s\n",zstring_replace_str(s,"ree","XYZ"));
    return 0;
}

Und unten ist die Ausgabe

Free software is a matter of liberty, not price.
To understand the concept, you should think of 'free' 
as in 'free speech', not as in 'free beer'

FXYZ software is a matter of liberty, not price.
To understand the concept, you should think of 'fXYZ' 
as in 'fXYZ speech', not as in 'fXYZ beer'
0
Fehmi Noyan ISI

Diese Funktion funktioniert nur, wenn der Ur-String zusätzlichen Platz für die neue Länge hat

void replace_str(char *str,char *org,char *rep)
{
    char *ToRep = strstr(str,org);
    char *Rest = (char*)malloc(strlen(ToRep));
    strcpy(Rest,((ToRep)+strlen(org)));

    strcpy(ToRep,rep);
    strcat(ToRep,Rest);

    free(Rest);
}

Dies ersetzt nur das erste Vorkommen 

0
noone